diff --git a/eval.c b/eval.c index ca4456d5d2..5d402e5cb8 100644 --- a/eval.c +++ b/eval.c @@ -1672,7 +1672,14 @@ void rb_obj_call_init(VALUE obj, int argc, const VALUE *argv) { PASS_PASSED_BLOCK_HANDLER(); - rb_funcallv_kw(obj, idInitialize, argc, argv, RB_PASS_CALLED_KEYWORDS); + rb_funcallv_kw(obj, idInitialize, argc, argv, RB_NO_KEYWORDS); +} + +void +rb_obj_call_init_kw(VALUE obj, int argc, const VALUE *argv, int kw_splat) +{ + PASS_PASSED_BLOCK_HANDLER(); + rb_funcallv_kw(obj, idInitialize, argc, argv, kw_splat); } /*! diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 4fa00d55e6..8a8392825c 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -443,7 +443,9 @@ void rb_provide(const char*); VALUE rb_f_require(VALUE, VALUE); VALUE rb_require_safe(VALUE, int); void rb_obj_call_init(VALUE, int, const VALUE*); +void rb_obj_call_init_kw(VALUE, int, const VALUE*, int); VALUE rb_class_new_instance(int, const VALUE*, VALUE); +VALUE rb_class_new_instance_kw(int, const VALUE*, VALUE, int); VALUE rb_block_proc(void); VALUE rb_block_lambda(void); VALUE rb_proc_new(rb_block_call_func_t, VALUE); @@ -456,7 +458,9 @@ VALUE rb_binding_new(void); VALUE rb_obj_method(VALUE, VALUE); VALUE rb_obj_is_method(VALUE); VALUE rb_method_call(int, const VALUE*, VALUE); +VALUE rb_method_call_kw(int, const VALUE*, VALUE, int); VALUE rb_method_call_with_block(int, const VALUE *, VALUE, VALUE); +VALUE rb_method_call_with_block_kw(int, const VALUE *, VALUE, VALUE, int); int rb_mod_method_arity(VALUE, ID); int rb_obj_method_arity(VALUE, ID); VALUE rb_protect(VALUE (*)(VALUE), VALUE, int*); diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 1b396f4c19..b60afde04c 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1901,6 +1901,7 @@ VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE); VALUE rb_funcall_with_block_kw(VALUE, ID, int, const VALUE*, VALUE, int); int rb_scan_args(int, const VALUE*, const char*, ...); VALUE rb_call_super(int, const VALUE*); +VALUE rb_call_super_kw(int, const VALUE*, int); VALUE rb_current_receiver(void); int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *); VALUE rb_extract_keywords(VALUE *orighash); diff --git a/object.c b/object.c index 501fcfcffa..de2d72fae3 100644 --- a/object.c +++ b/object.c @@ -2196,7 +2196,19 @@ rb_class_s_new(int argc, const VALUE *argv, VALUE klass) VALUE obj; obj = rb_class_alloc(klass); - rb_obj_call_init(obj, argc, argv); + rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS); + + return obj; +} + +VALUE +rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat) +{ + VALUE obj; + Check_Type(klass, T_CLASS); + + obj = rb_class_alloc(klass); + rb_obj_call_init_kw(obj, argc, argv, kw_splat); return obj; } @@ -2216,8 +2228,13 @@ rb_class_s_new(int argc, const VALUE *argv, VALUE klass) VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass) { + VALUE obj; Check_Type(klass, T_CLASS); - return rb_class_s_new(argc, argv, klass); + + obj = rb_class_alloc(klass); + rb_obj_call_init_kw(obj, argc, argv, RB_NO_KEYWORDS); + + return obj; } /** diff --git a/proc.c b/proc.c index 92264af2a7..62b8eadb8f 100644 --- a/proc.c +++ b/proc.c @@ -819,7 +819,7 @@ rb_proc_s_new(int argc, VALUE *argv, VALUE klass) { VALUE block = proc_new(klass, FALSE); - rb_obj_call_init(block, argc, argv); + rb_obj_call_init_kw(block, argc, argv, RB_PASS_CALLED_KEYWORDS); return block; } @@ -2204,6 +2204,20 @@ method_clone(VALUE self) * m.call(20) #=> 32 */ +static VALUE +rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method) +{ + VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil; + return rb_method_call_with_block_kw(argc, argv, method, procval, RB_PASS_CALLED_KEYWORDS); +} + +VALUE +rb_method_call_kw(int argc, const VALUE *argv, VALUE method, int kw_splat) +{ + VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil; + return rb_method_call_with_block_kw(argc, argv, method, procval, kw_splat); +} + VALUE rb_method_call(int argc, const VALUE *argv, VALUE method) { @@ -2220,17 +2234,17 @@ method_callable_method_entry(const struct METHOD *data) static inline VALUE call_method_data(rb_execution_context_t *ec, const struct METHOD *data, - int argc, const VALUE *argv, VALUE passed_procval) + int argc, const VALUE *argv, VALUE passed_procval, int kw_splat) { vm_passed_block_handler_set(ec, proc_to_block_handler(passed_procval)); return rb_vm_call_kw(ec, data->recv, data->me->called_id, argc, argv, - method_callable_method_entry(data), RB_PASS_CALLED_KEYWORDS); + method_callable_method_entry(data), kw_splat); } static VALUE call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data, int argc, const VALUE *argv, VALUE passed_procval, - int safe) + int safe, int kw_splat) { VALUE result = Qnil; /* OK */ enum ruby_tag_type state; @@ -2239,7 +2253,7 @@ call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data, if ((state = EC_EXEC_TAG()) == TAG_NONE) { /* result is used only if state == 0, no exceptions is caught. */ /* otherwise it doesn't matter even if clobbered. */ - NO_CLOBBERED(result) = call_method_data(ec, data, argc, argv, passed_procval); + NO_CLOBBERED(result) = call_method_data(ec, data, argc, argv, passed_procval, kw_splat); } EC_POP_TAG(); rb_set_safe_level_force(safe); @@ -2249,7 +2263,7 @@ call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data, } VALUE -rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passed_procval) +rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE method, VALUE passed_procval, int kw_splat) { const struct METHOD *data; rb_execution_context_t *ec = GET_EC(); @@ -2263,10 +2277,16 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe int safe = rb_safe_level(); if (safe < safe_level_to_run) { rb_set_safe_level_force(safe_level_to_run); - return call_method_data_safe(ec, data, argc, argv, passed_procval, safe); + return call_method_data_safe(ec, data, argc, argv, passed_procval, safe, kw_splat); } } - return call_method_data(ec, data, argc, argv, passed_procval); + return call_method_data(ec, data, argc, argv, passed_procval, kw_splat); +} + +VALUE +rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passed_procval) +{ + return rb_method_call_with_block_kw(argc, argv, method, passed_procval, RB_NO_KEYWORDS); } /********************************************************************** @@ -2439,7 +2459,7 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method) VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil; rb_execution_context_t *ec = GET_EC(); - return call_method_data(ec, &bound, argc, argv, passed_procval); + return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS); } /* @@ -3692,12 +3712,12 @@ Init_Proc(void) rb_define_method(rb_cMethod, "eql?", method_eq, 1); rb_define_method(rb_cMethod, "hash", method_hash, 0); rb_define_method(rb_cMethod, "clone", method_clone, 0); - rb_define_method(rb_cMethod, "call", rb_method_call, -1); - rb_define_method(rb_cMethod, "===", rb_method_call, -1); + rb_define_method(rb_cMethod, "call", rb_method_call_pass_called_kw, -1); + rb_define_method(rb_cMethod, "===", rb_method_call_pass_called_kw, -1); rb_define_method(rb_cMethod, "curry", rb_method_curry, -1); rb_define_method(rb_cMethod, "<<", rb_method_compose_to_left, 1); rb_define_method(rb_cMethod, ">>", rb_method_compose_to_right, 1); - rb_define_method(rb_cMethod, "[]", rb_method_call, -1); + rb_define_method(rb_cMethod, "[]", rb_method_call_pass_called_kw, -1); rb_define_method(rb_cMethod, "arity", method_arity_m, 0); rb_define_method(rb_cMethod, "inspect", method_inspect, 0); rb_define_method(rb_cMethod, "to_s", method_inspect, 0); diff --git a/thread.c b/thread.c index 6958897fc1..3b6ded9609 100644 --- a/thread.c +++ b/thread.c @@ -882,7 +882,7 @@ thread_s_new(int argc, VALUE *argv, VALUE klass) if (GET_VM()->main_thread->status == THREAD_KILLED) rb_raise(rb_eThreadError, "can't alloc thread"); - rb_obj_call_init(thread, argc, argv); + rb_obj_call_init_kw(thread, argc, argv, RB_PASS_CALLED_KEYWORDS); th = rb_thread_ptr(thread); if (!threadptr_initialized(th)) { rb_raise(rb_eThreadError, "uninitialized thread - check `%"PRIsVALUE"#initialize'", diff --git a/vm_eval.c b/vm_eval.c index 68a724834e..f1246537e7 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -269,7 +269,7 @@ rb_vm_call_kw(rb_execution_context_t *ec, VALUE recv, VALUE id, int argc, const } static inline VALUE -vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv) +vm_call_super(rb_execution_context_t *ec, int argc, const VALUE *argv, int kw_splat) { VALUE recv = ec->cfp->self; VALUE klass; @@ -290,16 +290,25 @@ 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, RB_PASS_CALLED_KEYWORDS); + add_empty_keyword(&argc, &argv, &kw_splat); + return rb_vm_call0(ec, recv, id, argc, argv, me, kw_splat); } } +VALUE +rb_call_super_kw(int argc, const VALUE *argv, int kw_splat) +{ + rb_execution_context_t *ec = GET_EC(); + PASS_PASSED_BLOCK_HANDLER_EC(ec); + return vm_call_super(ec, argc, argv, kw_splat); +} + VALUE rb_call_super(int argc, const VALUE *argv) { rb_execution_context_t *ec = GET_EC(); PASS_PASSED_BLOCK_HANDLER_EC(ec); - return vm_call_super(ec, argc, argv); + return vm_call_super(ec, argc, argv, RB_NO_KEYWORDS); } VALUE