summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-09-13 16:42:27 -0700
committerJeremy Evans <code@jeremyevans.net>2019-09-13 16:42:27 -0700
commit3cfbfa9628435e3b09316a18c2db9e4f250fdd77 (patch)
treeaac052f5a518c9b4aaf296da2a4730c72e5ed521 /vm_eval.c
parent24b1b339757ecab4539a2cb00a545bfcf885d3ef (diff)
Consolidate empty keyword handling
Remove rb_add_empty_keyword, and instead of calling that every place you need to add empty keyword hashes, run that code in a single static function in vm_eval.c. Add 4 defines to include/ruby/ruby.h, these are to be used as int kw_splat values when calling the various rb_*_kw functions: RB_NO_KEYWORDS :: Do not pass keywords RB_PASS_KEYWORDS :: Pass final argument (which should be hash) as keywords RB_PASS_EMPTY_KEYWORDS :: Add an empty hash to arguments and pass as keywords RB_PASS_CALLED_KEYWORDS :: Passes same keyword type as current method was called with (for method delegation) rb_empty_keyword_given_p needs to stay. It is required if argument delegation is done but delayed to a later point, which Enumerator does. Use RB_PASS_CALLED_KEYWORDS in rb_call_super to correctly delegate keyword arguments to super method.
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/vm_eval.c b/vm_eval.c
index 434e1dcd16..7609d191ef 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -235,6 +235,26 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, const
return ret;
}
+static void
+add_empty_keyword(int *argc, const VALUE **argv, int *kw_splat)
+{
+ if (*kw_splat == RB_PASS_CALLED_KEYWORDS || *kw_splat == RB_PASS_EMPTY_KEYWORDS) {
+ if (*kw_splat == RB_PASS_EMPTY_KEYWORDS || rb_empty_keyword_given_p()) {
+ int n = *argc;
+ VALUE *ptr = ALLOC_N(VALUE,n+1);
+
+ memcpy(ptr, *argv, sizeof(VALUE)*n);
+ ptr[n] = rb_hash_new();
+ *argc = ++n;
+ *argv = ptr;
+ *kw_splat = 1;
+ }
+ else {
+ *kw_splat = rb_keyword_given_p();
+ }
+ }
+}
+
VALUE
rb_vm_call(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
{
@@ -244,6 +264,7 @@ rb_vm_call(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const VAL
VALUE
rb_vm_call_kw(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me, int kw_splat)
{
+ add_empty_keyword(&argc, &argv, &kw_splat);
return rb_vm_call0(ec, recv, id, argc, argv, me, kw_splat);
}
@@ -269,7 +290,7 @@ vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv)
return method_missing(recv, id, argc, argv, MISSING_SUPER);
}
else {
- return rb_vm_call0(ec, recv, id, argc, argv, me, VM_NO_KEYWORDS);
+ return rb_vm_call0(ec, recv, id, argc, argv, me, RB_PASS_CALLED_KEYWORDS);
}
}
@@ -909,6 +930,7 @@ rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
VALUE
rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
{
+ add_empty_keyword(&argc, &argv, &kw_splat);
return rb_call(recv, mid, argc, argv, kw_splat ? CALL_FCALL_KW : CALL_FCALL);
}
@@ -976,6 +998,7 @@ rb_funcall_with_block_kw(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE
vm_passed_block_handler_set(GET_EC(), passed_procval);
}
+ add_empty_keyword(&argc, &argv, &kw_splat);
return rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC);
}
@@ -1340,6 +1363,7 @@ rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE * argv,
{
struct iter_method_arg arg;
+ add_empty_keyword(&argc, &argv, &kw_splat);
arg.obj = obj;
arg.mid = mid;
arg.argc = argc;