From beae6cbf0fd8b6619e5212552de98022d4c4d4d4 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 4 Oct 2019 12:51:57 -0700 Subject: Fully separate positional arguments and keyword arguments This removes the warnings added in 2.7, and changes the behavior so that a final positional hash is not treated as keywords or vice-versa. To handle the arg_setup_block splat case correctly with keyword arguments, we need to check if we are taking a keyword hash. That case didn't have a test, but it affects real-world code, so add a test for it. This removes rb_empty_keyword_given_p() and related code, as that is not needed in Ruby 3. The empty keyword case is the same as the no keyword case in Ruby 3. This changes rb_scan_args to implement keyword argument separation for C functions when the : character is used. For backwards compatibility, it returns a duped hash. This is a bad idea for performance, but not duping the hash breaks at least Enumerator::ArithmeticSequence#inspect. Instead of having RB_PASS_CALLED_KEYWORDS be a number, simplify the code by just making it be rb_keyword_given_p(). --- class.c | 70 +------ cont.c | 12 +- enumerator.c | 14 +- eval.c | 8 - ext/-test-/scan_args/scan_args.c | 10 - include/ruby/ruby.h | 78 +------- internal/vm.h | 1 - object.c | 4 +- proc.c | 5 - test/ruby/test_proc.rb | 10 + thread.c | 10 +- vm.c | 7 - vm_args.c | 383 ++++----------------------------------- vm_core.h | 12 +- vm_eval.c | 106 ++--------- vm_insnhelper.c | 45 +---- 16 files changed, 96 insertions(+), 679 deletions(-) diff --git a/class.c b/class.c index bc64ff7795..e42ee0821c 100644 --- a/class.c +++ b/class.c @@ -1970,7 +1970,6 @@ rb_scan_args_parse(int kw_flag, int argc, const VALUE *argv, const char *fmt, st const char *p = fmt; VALUE *tmp_buffer = arg->tmp_buffer; int keyword_given = 0; - int empty_keyword_given = 0; int last_hash_keyword = 0; memset(arg, 0, sizeof(*arg)); @@ -1979,16 +1978,11 @@ rb_scan_args_parse(int kw_flag, int argc, const VALUE *argv, const char *fmt, st switch (kw_flag) { case RB_SCAN_ARGS_PASS_CALLED_KEYWORDS: - if (!(keyword_given = rb_keyword_given_p())) { - empty_keyword_given = rb_empty_keyword_given_p(); - } + keyword_given = rb_keyword_given_p(); break; case RB_SCAN_ARGS_KEYWORDS: keyword_given = 1; break; - case RB_SCAN_ARGS_EMPTY_KEYWORDS: - empty_keyword_given = 1; - break; case RB_SCAN_ARGS_LAST_HASH_KEYWORDS: last_hash_keyword = 1; break; @@ -2023,67 +2017,13 @@ rb_scan_args_parse(int kw_flag, int argc, const VALUE *argv, const char *fmt, st } arg->n_mand = arg->n_lead + arg->n_trail; - /* capture an option hash - phase 1: pop */ - /* Ignore final positional hash if empty keywords given */ - if (argc > 0 && !(arg->f_hash && empty_keyword_given)) { + if (arg->f_hash && argc > 0) { VALUE last = argv[argc - 1]; - if (arg->f_hash && arg->n_mand < argc) { - if (keyword_given) { - if (!RB_TYPE_P(last, T_HASH)) { - rb_warn("Keyword flag set when calling rb_scan_args, but last entry is not a hash"); - } - else { - arg->hash = last; - } - } - else if (NIL_P(last)) { - /* For backwards compatibility, nil is taken as an empty - option hash only if it is not ambiguous; i.e. '*' is - not specified and arguments are given more than sufficient. - This will be removed in Ruby 3. */ - if (!arg->f_var && arg->n_mand + arg->n_opt < argc) { - rb_warn("The last argument is nil, treating as empty keywords"); - argc--; - } - } - else { - arg->hash = rb_check_hash_type(last); - } - - /* Ruby 3: Remove if branch, as it will not attempt to split hashes */ - if (!NIL_P(arg->hash)) { - VALUE opts = rb_extract_keywords(&arg->hash); - - if (!(arg->last_hash = arg->hash)) { - if (!keyword_given && !last_hash_keyword) { - /* Warn if treating positional as keyword, as in Ruby 3, - this will be an error */ - rb_warn("Using the last argument as keyword parameters is deprecated"); - } - argc--; - } - else { - /* Warn if splitting either positional hash to keywords or keywords - to positional hash, as in Ruby 3, no splitting will be done */ - rb_warn("The last argument is split into positional and keyword parameters"); - arg->last_idx = argc - 1; - } - arg->hash = opts ? opts : Qnil; - } + if (keyword_given || (last_hash_keyword && RB_TYPE_P(last, T_HASH))) { + arg->hash = rb_hash_dup(last); + argc--; } - else if (arg->f_hash && keyword_given && arg->n_mand == argc) { - /* Warn if treating keywords as positional, as in Ruby 3, this will be an error */ - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - } - } - if (arg->f_hash && arg->n_mand == argc+1 && empty_keyword_given) { - VALUE *ptr = rb_alloc_tmp_buffer2(tmp_buffer, argc+1, sizeof(VALUE)); - memcpy(ptr, argv, sizeof(VALUE)*argc); - ptr[argc] = rb_hash_new(); - argc++; - *(&argv) = ptr; - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); } arg->argc = argc; diff --git a/cont.c b/cont.c index 2365406d9e..d4a2bf9353 100644 --- a/cont.c +++ b/cont.c @@ -1790,8 +1790,6 @@ rb_fiber_new(rb_block_call_func_t func, VALUE obj) static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt); -#define PASS_KW_SPLAT (rb_empty_keyword_given_p() ? RB_PASS_EMPTY_KEYWORDS : rb_keyword_given_p()) - void rb_fiber_start(void) { @@ -1809,7 +1807,6 @@ rb_fiber_start(void) rb_context_t *cont = &VAR_FROM_MEMORY(fiber)->cont; int argc; const VALUE *argv, args = cont->value; - int kw_splat = cont->kw_splat; GetProcPtr(fiber->first_proc, proc); argv = (argc = cont->argc) > 1 ? RARRAY_CONST_PTR(args) : &args; cont->value = Qnil; @@ -1818,8 +1815,7 @@ rb_fiber_start(void) th->ec->root_svar = Qfalse; EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, 0, Qnil); - rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - cont->value = rb_vm_invoke_proc(th->ec, proc, argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE); + cont->value = rb_vm_invoke_proc(th->ec, proc, argc, argv, cont->kw_splat, VM_BLOCK_HANDLER_NONE); } EC_POP_TAG(); @@ -2163,7 +2159,7 @@ rb_fiber_alive_p(VALUE fiber_value) static VALUE rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber) { - return rb_fiber_resume_kw(fiber, argc, argv, PASS_KW_SPLAT); + return rb_fiber_resume_kw(fiber, argc, argv, rb_keyword_given_p()); } /* @@ -2249,7 +2245,7 @@ rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value) { rb_fiber_t *fiber = fiber_ptr(fiber_value); fiber->transferred = 1; - return fiber_switch(fiber, argc, argv, 0, PASS_KW_SPLAT); + return fiber_switch(fiber, argc, argv, 0, rb_keyword_given_p()); } /* @@ -2265,7 +2261,7 @@ rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fiber_value) static VALUE rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass) { - return rb_fiber_yield_kw(argc, argv, PASS_KW_SPLAT); + return rb_fiber_yield_kw(argc, argv, rb_keyword_given_p()); } /* diff --git a/enumerator.c b/enumerator.c index 790818064f..fa30a59819 100644 --- a/enumerator.c +++ b/enumerator.c @@ -384,8 +384,6 @@ enumerator_allocate(VALUE klass) return enum_obj; } -#define PASS_KW_SPLAT (rb_empty_keyword_given_p() ? RB_PASS_EMPTY_KEYWORDS : rb_keyword_given_p()) - static VALUE enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, VALUE size, int kw_splat) { @@ -480,7 +478,7 @@ enumerator_initialize(int argc, VALUE *argv, VALUE obj) meth = *argv++; --argc; } - kw_splat = PASS_KW_SPLAT; + kw_splat = rb_keyword_given_p(); } return enumerator_init(obj, recv, meth, argc, argv, 0, size, kw_splat); @@ -535,10 +533,10 @@ rb_enumeratorize_with_size(VALUE obj, VALUE meth, int argc, const VALUE *argv, r /* Similar effect as calling obj.to_enum, i.e. dispatching to either Kernel#to_enum vs Lazy#to_enum */ if (RTEST(rb_obj_is_kind_of(obj, rb_cLazy))) - return lazy_to_enum_i(obj, meth, argc, argv, size_fn, PASS_KW_SPLAT); + return lazy_to_enum_i(obj, meth, argc, argv, size_fn, rb_keyword_given_p()); else return enumerator_init(enumerator_allocate(rb_cEnumerator), - obj, meth, argc, argv, size_fn, Qnil, PASS_KW_SPLAT); + obj, meth, argc, argv, size_fn, Qnil, rb_keyword_given_p()); } VALUE @@ -1892,7 +1890,7 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo, static VALUE enumerable_lazy(VALUE obj) { - VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, PASS_KW_SPLAT); + VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, rb_keyword_given_p()); /* Qfalse indicates that the Enumerator::Lazy has no method name */ rb_ivar_set(result, id_method, Qfalse); return result; @@ -1940,7 +1938,7 @@ lazy_to_enum(int argc, VALUE *argv, VALUE self) if (RTEST((super_meth = rb_hash_aref(lazy_use_super_method, meth)))) { meth = super_meth; } - lazy = lazy_to_enum_i(self, meth, argc, argv, 0, PASS_KW_SPLAT); + lazy = lazy_to_enum_i(self, meth, argc, argv, 0, rb_keyword_given_p()); if (rb_block_given_p()) { enumerator_ptr(lazy)->size = rb_block_proc(); } @@ -3318,7 +3316,7 @@ rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv, VALUE beg, VALUE end, VALUE step, int excl) { VALUE aseq = enumerator_init(enumerator_allocate(rb_cArithSeq), - obj, meth, argc, argv, size_fn, Qnil, PASS_KW_SPLAT); + obj, meth, argc, argv, size_fn, Qnil, rb_keyword_given_p()); rb_ivar_set(aseq, id_begin, beg); rb_ivar_set(aseq, id_end, end); rb_ivar_set(aseq, id_step, step); diff --git a/eval.c b/eval.c index 4770327a72..429ecbe0d9 100644 --- a/eval.c +++ b/eval.c @@ -924,14 +924,6 @@ rb_keyword_given_p(void) return rb_vm_cframe_keyword_p(GET_EC()->cfp); } -/* -- Remove In 3.0 -- */ -int rb_vm_cframe_empty_keyword_p(const rb_control_frame_t *cfp); -int -rb_empty_keyword_given_p(void) -{ - return rb_vm_cframe_empty_keyword_p(GET_EC()->cfp); -} - VALUE rb_eThreadError; /*! Declares that the current method needs a block. diff --git a/ext/-test-/scan_args/scan_args.c b/ext/-test-/scan_args/scan_args.c index 9c374da66f..8696aad3c7 100644 --- a/ext/-test-/scan_args/scan_args.c +++ b/ext/-test-/scan_args/scan_args.c @@ -259,15 +259,6 @@ scan_args_k_lead_opt_hash(int argc, VALUE *argv, VALUE self) return rb_ary_new_from_values(numberof(args), args); } -static VALUE -scan_args_e_lead_opt_hash(int argc, VALUE *argv, VALUE self) -{ - VALUE args[4]; - int n = rb_scan_args_kw(RB_SCAN_ARGS_EMPTY_KEYWORDS, argc, argv, "11:", args+1, args+2, args+3); - args[0] = INT2NUM(n); - return rb_ary_new_from_values(numberof(args), args); -} - static VALUE scan_args_n_lead_opt_hash(int argc, VALUE *argv, VALUE self) { @@ -310,6 +301,5 @@ Init_scan_args(void) rb_define_singleton_method(module, "opt_var_trail_hash", scan_args_opt_var_trail_hash, -1); rb_define_singleton_method(module, "lead_opt_var_trail_hash", scan_args_lead_opt_var_trail_hash, -1); rb_define_singleton_method(module, "k_lead_opt_hash", scan_args_k_lead_opt_hash, -1); - rb_define_singleton_method(module, "e_lead_opt_hash", scan_args_e_lead_opt_hash, -1); rb_define_singleton_method(module, "n_lead_opt_hash", scan_args_n_lead_opt_hash, -1); } diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 9b7c9842f8..d81c72e95b 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1901,7 +1901,6 @@ VALUE rb_funcall_with_block_kw(VALUE, ID, int, const VALUE*, VALUE, int); int rb_scan_args(int, const VALUE*, const char*, ...); #define RB_SCAN_ARGS_PASS_CALLED_KEYWORDS 0 #define RB_SCAN_ARGS_KEYWORDS 1 -#define RB_SCAN_ARGS_EMPTY_KEYWORDS 2 /* Will be removed in 3.0 */ #define RB_SCAN_ARGS_LAST_HASH_KEYWORDS 3 int rb_scan_args_kw(int, int, const VALUE*, const char*, ...); VALUE rb_call_super(int, const VALUE*); @@ -1976,8 +1975,7 @@ VALUE rb_yield_splat_kw(VALUE, int); VALUE rb_yield_block(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)); /* rb_block_call_func */ #define RB_NO_KEYWORDS 0 #define RB_PASS_KEYWORDS 1 -#define RB_PASS_EMPTY_KEYWORDS 2 /* Will be removed in 3.0 */ -#define RB_PASS_CALLED_KEYWORDS 3 +#define RB_PASS_CALLED_KEYWORDS rb_keyword_given_p() int rb_keyword_given_p(void); int rb_block_given_p(void); void rb_need_block(void); @@ -2331,9 +2329,6 @@ unsigned long ruby_strtoul(const char *str, char **endptr, int base); PRINTF_ARGS(int ruby_snprintf(char *str, size_t n, char const *fmt, ...), 3, 4); int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap); -/* -- Remove In 3.0, Only public for rb_scan_args optimized version -- */ -int rb_empty_keyword_given_p(void); - #if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P) && defined(HAVE_VA_ARGS_MACRO) && defined(__OPTIMIZE__) # define rb_scan_args(argc,argvp,fmt,...) \ __builtin_choose_expr(__builtin_constant_p(fmt), \ @@ -2525,78 +2520,13 @@ rb_scan_args_set(int argc, const VALUE *argv, int i, argi = 0, vari = 0, last_idx = -1; VALUE *var, hash = Qnil, last_hash = 0; const int n_mand = n_lead + n_trail; - int keyword_given = rb_keyword_given_p(); - int empty_keyword_given = 0; VALUE tmp_buffer = 0; - if (!keyword_given) { - empty_keyword_given = rb_empty_keyword_given_p(); + if (f_hash && argc > 0 && rb_keyword_given_p()) { + hash = rb_hash_dup(argv[argc - 1]); + argc--; } - /* capture an option hash - phase 1: pop */ - /* Ignore final positional hash if empty keywords given */ - if (argc > 0 && !(f_hash && empty_keyword_given)) { - VALUE last = argv[argc - 1]; - - if (f_hash && n_mand < argc) { - if (keyword_given) { - if (!RB_TYPE_P(last, T_HASH)) { - rb_warn("Keyword flag set when calling rb_scan_args, but last entry is not a hash"); - } - else { - hash = last; - } - } - else if (NIL_P(last)) { - /* For backwards compatibility, nil is taken as an empty - option hash only if it is not ambiguous; i.e. '*' is - not specified and arguments are given more than sufficient. - This will be removed in Ruby 3. */ - if (!f_var && n_mand + n_opt < argc) { - rb_warn("The last argument is nil, treating as empty keywords"); - argc--; - } - } - else { - hash = rb_check_hash_type(last); - } - - /* Ruby 3: Remove if branch, as it will not attempt to split hashes */ - if (!NIL_P(hash)) { - VALUE opts = rb_extract_keywords(&hash); - - if (!(last_hash = hash)) { - if (!keyword_given) { - /* Warn if treating positional as keyword, as in Ruby 3, - this will be an error */ - rb_warn("Using the last argument as keyword parameters is deprecated"); - } - argc--; - } - else { - /* Warn if splitting either positional hash to keywords or keywords - to positional hash, as in Ruby 3, no splitting will be done */ - rb_warn("The last argument is split into positional and keyword parameters"); - last_idx = argc - 1; - } - hash = opts ? opts : Qnil; - } - } - else if (f_hash && keyword_given && n_mand == argc) { - /* Warn if treating keywords as positional, as in Ruby 3, this will be an error */ - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - } - } - if (f_hash && n_mand > 0 && n_mand == argc+1 && empty_keyword_given) { - VALUE *ptr = (VALUE *)rb_alloc_tmp_buffer2(&tmp_buffer, argc+1, sizeof(VALUE)); - memcpy(ptr, argv, sizeof(VALUE)*argc); - ptr[argc] = rb_hash_new(); - argc++; - *(&argv) = ptr; - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - } - - if (argc < n_mand) { goto argc_error; } diff --git a/internal/vm.h b/internal/vm.h index 1bd7a98f7a..c5986a1c24 100644 --- a/internal/vm.h +++ b/internal/vm.h @@ -138,7 +138,6 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, MJIT_SYMBOL_EXPORT_BEGIN VALUE rb_vm_call0(struct rb_execution_context_struct *ec, VALUE recv, ID id, int argc, const VALUE *argv, const struct rb_callable_method_entry_struct *me, int kw_splat); -VALUE rb_adjust_argv_kw_splat(int *argc, const VALUE **argv, int *kw_splat); VALUE rb_vm_call_kw(struct rb_execution_context_struct *ec, VALUE recv, VALUE id, int argc, const VALUE *argv, const struct rb_callable_method_entry_struct *me, int kw_splat); VALUE rb_make_no_method_exception(VALUE exc, VALUE format, VALUE obj, int argc, const VALUE *argv, int priv); MJIT_SYMBOL_EXPORT_END diff --git a/object.c b/object.c index b5514322d2..f02b45af1c 100644 --- a/object.c +++ b/object.c @@ -4086,9 +4086,7 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound) } return rb_check_funcall_with_hook_kw(obj, id_dig, argc, argv, no_dig_method, obj, - rb_empty_keyword_given_p() ? - RB_PASS_EMPTY_KEYWORDS : - RB_NO_KEYWORDS); + RB_NO_KEYWORDS); } return obj; } diff --git a/proc.c b/proc.c index 7094a021f3..5434e8daa7 100644 --- a/proc.c +++ b/proc.c @@ -955,14 +955,11 @@ rb_proc_call_kw(VALUE self, VALUE args, int kw_splat) { VALUE vret; rb_proc_t *proc; - VALUE v; int argc = check_argc(RARRAY_LEN(args)); const VALUE *argv = RARRAY_CONST_PTR(args); GetProcPtr(self, proc); - v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); vret = rb_vm_invoke_proc(GET_EC(), proc, argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE); - rb_free_tmp_buffer(&v); RB_GC_GUARD(self); RB_GC_GUARD(args); return vret; @@ -994,10 +991,8 @@ rb_proc_call_with_block_kw(VALUE self, int argc, const VALUE *argv, VALUE passed rb_execution_context_t *ec = GET_EC(); VALUE vret; rb_proc_t *proc; - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); GetProcPtr(self, proc); vret = rb_vm_invoke_proc(ec, proc, argc, argv, kw_splat, proc_to_block_handler(passed_procval)); - rb_free_tmp_buffer(&v); RB_GC_GUARD(self); return vret; } diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index 1f84b2eb84..fce1bd4a87 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -1087,6 +1087,16 @@ class TestProc < Test::Unit::TestCase assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]") end + def test_proc_single_arg_with_keywords_accepted_and_yielded + def self.a + yield [], **{a: 1} + end + res = a do |arg, **opts| + [arg, opts] + end + assert_equal([[], {a: 1}], res) + end + def test_parameters assert_equal([], proc {}.parameters) assert_equal([], proc {||}.parameters) diff --git a/thread.c b/thread.c index 16f3e1ffed..4faf04c1ce 100644 --- a/thread.c +++ b/thread.c @@ -681,7 +681,6 @@ thread_do_start(rb_thread_t *th) if (th->invoke_type == thread_invoke_type_proc) { VALUE args = th->invoke_arg.proc.args; int args_len = (int)RARRAY_LEN(args); - int kw_splat = th->invoke_arg.proc.kw_splat; const VALUE *args_ptr; VALUE procval = th->invoke_arg.proc.proc; rb_proc_t *proc; @@ -704,10 +703,11 @@ thread_do_start(rb_thread_t *th) args_ptr = RARRAY_CONST_PTR(args); } - rb_adjust_argv_kw_splat(&args_len, &args_ptr, &kw_splat); + vm_check_ints_blocking(th->ec); th->value = rb_vm_invoke_proc(th->ec, proc, args_len, args_ptr, - kw_splat, VM_BLOCK_HANDLER_NONE); + th->invoke_arg.proc.kw_splat, + VM_BLOCK_HANDLER_NONE); EXEC_EVENT_HOOK(th->ec, RUBY_EVENT_THREAD_END, th->self, 0, 0, 0, Qundef); } @@ -856,9 +856,7 @@ thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(void *)) th->invoke_type = thread_invoke_type_proc; th->invoke_arg.proc.proc = rb_block_proc(); th->invoke_arg.proc.args = args; - th->invoke_arg.proc.kw_splat = rb_empty_keyword_given_p() ? - RB_PASS_EMPTY_KEYWORDS : - rb_keyword_given_p(); + th->invoke_arg.proc.kw_splat = rb_keyword_given_p(); } th->priority = current_th->priority; diff --git a/vm.c b/vm.c index e432cb13aa..5dd78a5e83 100644 --- a/vm.c +++ b/vm.c @@ -119,13 +119,6 @@ rb_vm_cframe_keyword_p(const rb_control_frame_t *cfp) return VM_FRAME_CFRAME_KW_P(cfp); } -/* -- Remove In 3.0 -- */ -int -rb_vm_cframe_empty_keyword_p(const rb_control_frame_t *cfp) -{ - return VM_FRAME_CFRAME_EMPTY_KW_P(cfp); -} - VALUE rb_vm_frame_block_handler(const rb_control_frame_t *cfp) { diff --git a/vm_args.c b/vm_args.c index 7bf61cefe7..3558d6487f 100644 --- a/vm_args.c +++ b/vm_args.c @@ -187,124 +187,6 @@ args_rest_array(struct args_info *args) return ary; } -#define KW_HASH_HAS_NO_KEYS 0 -#define KW_HASH_HAS_SYMBOL_KEY 1 -#define KW_HASH_HAS_OTHER_KEY 2 -#define KW_HASH_HAS_BOTH_KEYS 3 - -static int -keyword_hash_symbol_other_iter(st_data_t key, st_data_t val, st_data_t arg) -{ - *(int*)arg |= SYMBOL_P((VALUE)key) ? KW_HASH_HAS_SYMBOL_KEY : KW_HASH_HAS_OTHER_KEY; - - if ((*(int*)arg & KW_HASH_HAS_BOTH_KEYS) == KW_HASH_HAS_BOTH_KEYS) { - return ST_STOP; - } - - return ST_CONTINUE; -} - -static int -keyword_hash_symbol_other(VALUE hash) -{ - int symbol_other = KW_HASH_HAS_NO_KEYS; - rb_hash_stlike_foreach(hash, keyword_hash_symbol_other_iter, (st_data_t)(&symbol_other)); - return symbol_other; -} - -static int -keyword_hash_split_iter(st_data_t key, st_data_t val, st_data_t arg) -{ - if (SYMBOL_P((VALUE)key)) { - rb_hash_aset((VALUE)arg, (VALUE)key, (VALUE)val); - return ST_DELETE; - } - - return ST_CONTINUE; -} - -static void -keyword_hash_split(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr) -{ - *kw_hash_ptr = rb_hash_new(); - rb_hash_stlike_foreach(*rest_hash_ptr, keyword_hash_split_iter, (st_data_t)(*kw_hash_ptr)); -} - -static int -keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, int check_only_symbol) -{ - *rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr); - - if (!NIL_P(*rest_hash_ptr)) { - if (check_only_symbol) { - switch (keyword_hash_symbol_other(*rest_hash_ptr)) { - case KW_HASH_HAS_NO_KEYS: - case KW_HASH_HAS_SYMBOL_KEY: - break; - case KW_HASH_HAS_OTHER_KEY: - *kw_hash_ptr = Qnil; - return FALSE; - case KW_HASH_HAS_BOTH_KEYS: - *rest_hash_ptr = rb_hash_dup(*rest_hash_ptr); - keyword_hash_split(kw_hash_ptr, rest_hash_ptr); - return TRUE; - } - } - *kw_hash_ptr = *rest_hash_ptr; - *rest_hash_ptr = Qfalse; - return TRUE; - } - else { - *kw_hash_ptr = Qnil; - return FALSE; - } -} - -static VALUE -args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, int check_only_symbol) -{ - VALUE rest_hash; - - if (args->rest == Qfalse) { - from_argv: - VM_ASSERT(args->argc > 0); - *kw_hash_ptr = args->argv[args->argc-1]; - - if (keyword_hash_p(kw_hash_ptr, &rest_hash, check_only_symbol)) { - if (rest_hash) { - args->argv[args->argc-1] = rest_hash; - } - else { - args->argc--; - return TRUE; - } - } - } - else { - long len = RARRAY_LEN(args->rest); - - if (len > 0) { - *kw_hash_ptr = RARRAY_AREF(args->rest, len - 1); - - if (keyword_hash_p(kw_hash_ptr, &rest_hash, check_only_symbol)) { - if (rest_hash) { - RARRAY_ASET(args->rest, len - 1, rest_hash); - } - else { - arg_rest_dup(args); - rb_ary_pop(args->rest); - return TRUE; - } - } - } - else { - goto from_argv; - } - } - - return FALSE; -} - static int args_kw_argv_to_hash(struct args_info *args) { @@ -572,149 +454,10 @@ fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr) static inline int ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq) { - if (!(iseq->body->param.flags.has_kw) && - !(iseq->body->param.flags.has_kwrest)) { - keyword_hash = rb_check_hash_type(keyword_hash); - - if (!NIL_P(keyword_hash) && RHASH_EMPTY_P(keyword_hash)) { - return 1; - } - } - - return 0; -} - -VALUE rb_iseq_location(const rb_iseq_t *iseq); - -/* -- Remove In 3.0 -- */ - -/* This is a map from caller PC to a set of callee methods. - * When a warning about keyword argument change is printed, - * it keeps the pair of callee and caller. - */ -static st_table *caller_to_callees = 0; - -static VALUE -rb_warn_check(const rb_execution_context_t * const ec, const rb_iseq_t *const iseq) -{ - if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) return 1; - - if (!iseq) return 0; - - const st_data_t callee = (st_data_t)(iseq->body->iseq_unique_id * 2); - - const rb_control_frame_t * const cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp); - - if (!cfp) return 0; - - const st_data_t caller = (st_data_t)cfp->pc; - - if (!caller_to_callees) { - caller_to_callees = st_init_numtable(); - } - - st_data_t val; - if (st_lookup(caller_to_callees, caller, &val)) { - st_table *callees; - - if (val & 1) { - val &= ~(st_data_t)1; - if (val == callee) return 1; /* already warned */ - - callees = st_init_numtable(); - st_insert(callees, val, 1); - } - else { - callees = (st_table *) val; - if (st_is_member(callees, callee)) return 1; /* already warned */ - } - st_insert(callees, callee, 1); - st_insert(caller_to_callees, caller, (st_data_t) callees); - } - else { - st_insert(caller_to_callees, caller, callee | 1); - } - - return 0; /* not warned yet for the pair of caller and callee */ -} - -static inline void -rb_warn_keyword_to_last_hash(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq) -{ - if (rb_warn_check(ec, iseq)) return; - - VALUE name, loc; - if (calling->recv == Qundef) { - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - return; - } - name = rb_id2str(ci->mid); - loc = rb_iseq_location(iseq); - if (NIL_P(loc)) { - rb_warn("Passing the keyword argument for `%"PRIsVALUE"' as the last hash parameter is deprecated", - name); - } - else { - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - if (name) { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method `%"PRIsVALUE"' is defined here", name); - } - else { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method is defined here"); - } - } -} - -static inline void -rb_warn_split_last_hash_to_keyword(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq) -{ - if (rb_warn_check(ec, iseq)) return; - - VALUE name, loc; - name = rb_id2str(ci->mid); - loc = rb_iseq_location(iseq); - if (NIL_P(loc)) { - rb_warn("Splitting the last argument for `%"PRIsVALUE"' into positional and keyword parameters is deprecated", - name); - } - else { - rb_warn("Splitting the last argument into positional and keyword parameters is deprecated"); - if (calling->recv != Qundef) { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method `%"PRIsVALUE"' is defined here", name); - } - else { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method is defined here"); - } - } -} - -static inline void -rb_warn_last_hash_to_keyword(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq) -{ - if (rb_warn_check(ec, iseq)) return; - - VALUE name, loc; - name = rb_id2str(ci->mid); - loc = rb_iseq_location(iseq); - if (NIL_P(loc)) { - rb_warn("Using the last argument for `%"PRIsVALUE"' as keyword parameters is deprecated; maybe ** should be added to the call", - name); - } - else { - rb_warn("Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call"); - if (calling->recv != Qundef) { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method `%"PRIsVALUE"' is defined here", name); - } - else { - rb_compile_warn(RSTRING_PTR(RARRAY_AREF(loc, 0)), FIX2INT(RARRAY_AREF(loc, 1)), - "The called method is defined here"); - } - } + return !(iseq->body->param.flags.has_kw) && + !(iseq->body->param.flags.has_kwrest) && + RB_TYPE_P(keyword_hash, T_HASH) && + RHASH_EMPTY_P(keyword_hash); } static int @@ -727,7 +470,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co const int max_argc = (iseq->body->param.flags.has_rest == FALSE) ? min_argc + iseq->body->param.opt_num : UNLIMITED_ARGUMENTS; int opt_pc = 0; int given_argc; - int kw_splat = FALSE; unsigned int kw_flag = ci->flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT); struct args_info args_body, *args; VALUE keyword_hash = Qnil; @@ -813,46 +555,47 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co if (kw_flag & VM_CALL_KW_SPLAT) { if (len > 0 && ignore_keyword_hash_p(rest_last, iseq)) { - if (given_argc != min_argc) { - if (remove_empty_keyword_hash) { - arg_rest_dup(args); - rb_ary_pop(args->rest); - given_argc--; - kw_flag &= ~VM_CALL_KW_SPLAT; - } - else { - flag_keyword_hash = rest_last; - } + if (remove_empty_keyword_hash) { + arg_rest_dup(args); + rb_ary_pop(args->rest); + given_argc--; + kw_flag &= ~VM_CALL_KW_SPLAT; } else { - rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); + flag_keyword_hash = rest_last; } } else if (!remove_empty_keyword_hash && rest_last) { flag_keyword_hash = rest_last; } + else if (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) { + arg_rest_dup(args); + rb_ary_pop(args->rest); + given_argc--; + keyword_hash = rest_last; + } } } else { if (kw_flag & VM_CALL_KW_SPLAT) { VALUE last_arg = args->argv[args->argc-1]; if (ignore_keyword_hash_p(last_arg, iseq)) { - if (given_argc != min_argc) { - if (remove_empty_keyword_hash) { - args->argc--; - given_argc--; - kw_flag &= ~VM_CALL_KW_SPLAT; - } - else { - flag_keyword_hash = last_arg; - } + if (remove_empty_keyword_hash) { + args->argc--; + given_argc--; + kw_flag &= ~VM_CALL_KW_SPLAT; } else { - rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); + flag_keyword_hash = last_arg; } } else if (!remove_empty_keyword_hash) { - flag_keyword_hash = args->argv[args->argc-1]; + flag_keyword_hash = last_arg; + } + else if (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) { + args->argc--; + given_argc--; + keyword_hash = last_arg; } } args->rest = Qfalse; @@ -870,7 +613,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co case arg_setup_method: break; /* do nothing special */ case arg_setup_block: - if (given_argc == 1 && + if (given_argc == (keyword_hash == Qnil ? 1 : 2) && (min_argc > 0 || iseq->body->param.opt_num > 1 || iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) && !iseq->body->param.flags.ambiguous_param0 && @@ -882,60 +625,13 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co /* argc check */ if (given_argc < min_argc) { - if (given_argc == min_argc - 1 && args->kw_argv) { - args_stored_kw_argv_to_hash(args); - given_argc = args_argc(args); - } - else { - if (arg_setup_type == arg_setup_block) { - CHECK_VM_STACK_OVERFLOW(ec->cfp, min_argc); - given_argc = min_argc; - args_extend(args, min_argc); - } - else { - argument_arity_error(ec, iseq, given_argc, min_argc, max_argc); - } - } - } - - if (kw_flag & VM_CALL_KW_SPLAT) { - kw_splat = !iseq->body->param.flags.has_rest; - } - if ((iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest || - (kw_splat && given_argc > max_argc)) && - args->kw_argv == NULL) { - if (given_argc > min_argc) { - if (kw_flag) { - int check_only_symbol = (kw_flag & VM_CALL_KW_SPLAT) && - iseq->body->param.flags.has_kw && - !iseq->body->param.flags.has_kwrest; - - if (args_pop_keyword_hash(args, &keyword_hash, check_only_symbol)) { - given_argc--; - } - else if (check_only_symbol) { - if (keyword_hash != Qnil) { - rb_warn_split_last_hash_to_keyword(ec, calling, ci, iseq); - } - else { - rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); - } - } - } - else if (args_pop_keyword_hash(args, &keyword_hash, 1)) { - /* Warn the following: - * def foo(k:1) p [k]; end - * foo({k:42}) #=> 42 - */ - rb_warn_last_hash_to_keyword(ec, calling, ci, iseq); - given_argc--; - } - else if (keyword_hash != Qnil) { - rb_warn_split_last_hash_to_keyword(ec, calling, ci, iseq); - } + if (arg_setup_type == arg_setup_block) { + CHECK_VM_STACK_OVERFLOW(ec->cfp, min_argc); + given_argc = min_argc; + args_extend(args, min_argc); } - else if (given_argc == min_argc && kw_flag) { - rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); + else { + argument_arity_error(ec, iseq, given_argc, min_argc, max_argc); } } @@ -1160,8 +856,6 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) const VALUE symbol = RARRAY_AREF(callback_arg, 0); const VALUE refinements = RARRAY_AREF(callback_arg, 1); int kw_splat = RB_PASS_CALLED_KEYWORDS; - VALUE v; - VALUE ret; VALUE klass; if (argc-- < 1) { @@ -1182,15 +876,10 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) if (!NIL_P(blockarg)) { vm_passed_block_handler_set(ec, blockarg); } - v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); if (!me) { - ret = method_missing(obj, mid, argc, argv, MISSING_NOENTRY, kw_splat); - } - else { - ret = rb_vm_call0(ec, obj, mid, argc, argv, me, kw_splat); + return method_missing(obj, mid, argc, argv, MISSING_NOENTRY, kw_splat); } - rb_free_tmp_buffer(&v); - return ret; + return rb_vm_call0(ec, obj, mid, argc, argv, me, kw_splat); } static VALUE diff --git a/vm_core.h b/vm_core.h index 8807c23b6f..70575fa66b 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1159,11 +1159,11 @@ typedef rb_control_frame_t * enum { /* Frame/Environment flag bits: - * MMMM MMMM MMMM MMMM ____ FFFF FFFF EEEX (LSB) + * MMMM MMMM MMMM MMMM ____ _FFF FFFF EEEX (LSB) * * X : tag for GC marking (It seems as Fixnum) * EEE : 3 bits Env flags - * FF..: 8 bits Frame flags + * FF..: 7 bits Frame flags * MM..: 15 bits frame magic (to check frame corruption) */ @@ -1188,7 +1188,6 @@ enum { VM_FRAME_FLAG_LAMBDA = 0x0100, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200, VM_FRAME_FLAG_CFRAME_KW = 0x0400, - VM_FRAME_FLAG_CFRAME_EMPTY_KW = 0x0800, /* -- Remove In 3.0 -- */ /* env flag */ VM_ENV_FLAG_LOCAL = 0x0002, @@ -1249,13 +1248,6 @@ VM_FRAME_CFRAME_KW_P(const rb_control_frame_t *cfp) return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME_KW) != 0; } -/* -- Remove In 3.0 -- */ -static inline int -VM_FRAME_CFRAME_EMPTY_KW_P(const rb_control_frame_t *cfp) -{ - return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME_EMPTY_KW) != 0; -} - static inline int VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp) { diff --git a/vm_eval.c b/vm_eval.c index 24d8dcfdf6..cbed304e25 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -69,7 +69,6 @@ vm_call0_cfunc_with_frame(rb_execution_context_t* ec, struct rb_calling_info *ca if (calling->kw_splat) { if (argc > 0 && RB_TYPE_P(argv[argc-1], T_HASH) && RHASH_EMPTY_P(argv[argc-1])) { - frame_flags |= VM_FRAME_FLAG_CFRAME_EMPTY_KW; argc--; } else { @@ -144,12 +143,7 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struc calling->argc > 0 && RB_TYPE_P(argv[calling->argc-1], T_HASH) && RHASH_EMPTY_P(argv[calling->argc-1])) { - if (calling->argc == 1) { - rb_warn("Passing the keyword argument as the last hash parameter is deprecated"); - } - else { - calling->argc--; - } + calling->argc--; } rb_check_arity(calling->argc, 1, 1); @@ -232,42 +226,10 @@ vm_call0_body(rb_execution_context_t *ec, struct rb_calling_info *calling, struc return ret; } -/* Caller should keep the reference to the return value until argv becomes useless. */ -MJIT_FUNC_EXPORTED VALUE -rb_adjust_argv_kw_splat(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 v; - VALUE *ptr = rb_alloc_tmp_buffer2(&v, n+1, sizeof(VALUE)); - if (n) memcpy(ptr, *argv, sizeof(VALUE)*n); - ptr[n] = rb_hash_new(); - *argc = ++n; - *argv = ptr; - *kw_splat = 1; - return v; - } - else { - *kw_splat = rb_keyword_given_p(); - } - } - - if (*kw_splat && (*argc == 0 || !RB_TYPE_P((*argv)[(*argc)-1], T_HASH))) { - rb_warn("Keyword flag passed calling internal method, but last entry is not a hash, unsetting keyword flag"); - *kw_splat = 0; - } - - return 0; -} - MJIT_FUNC_EXPORTED 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) { - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = rb_vm_call0(ec, recv, id, argc, argv, me, kw_splat); - rb_free_tmp_buffer(&v); - return ret; + return rb_vm_call0(ec, recv, id, argc, argv, me, kw_splat); } static inline VALUE @@ -961,10 +923,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) { - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = rb_call(recv, mid, argc, argv, kw_splat ? CALL_FCALL_KW : CALL_FCALL); - rb_free_tmp_buffer(&v); - return ret; + return rb_call(recv, mid, argc, argv, kw_splat ? CALL_FCALL_KW : CALL_FCALL); } /*! @@ -985,10 +944,7 @@ rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv) VALUE rb_funcallv_public_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat) { - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); - rb_free_tmp_buffer(&v); - return ret; + return rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); } /*! @@ -1038,12 +994,8 @@ rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv) VALUE rb_funcall_passing_block_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat) { - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret; PASS_PASSED_BLOCK_HANDLER(); - ret = rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); - rb_free_tmp_buffer(&v); - return ret; + return rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); } VALUE @@ -1063,10 +1015,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); } - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); - rb_free_tmp_buffer(&v); - return ret; + return rb_call(recv, mid, argc, argv, kw_splat ? CALL_PUBLIC_KW : CALL_PUBLIC); } static VALUE * @@ -1140,10 +1089,7 @@ send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope) static VALUE send_internal_kw(int argc, const VALUE *argv, VALUE recv, call_type scope) { - VALUE v=0, ret; - int kw_splat = RB_PASS_CALLED_KEYWORDS; - v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - if (kw_splat) { + if (rb_keyword_given_p()) { switch (scope) { case CALL_PUBLIC: scope = CALL_PUBLIC_KW; @@ -1155,9 +1101,7 @@ send_internal_kw(int argc, const VALUE *argv, VALUE recv, call_type scope) break; } } - ret = send_internal(argc, argv, recv, scope); - rb_free_tmp_buffer(&v); - return ret; + return send_internal(argc, argv, recv, scope); } /* @@ -1215,10 +1159,7 @@ rb_f_public_send(int argc, VALUE *argv, VALUE recv) static inline VALUE rb_yield_0_kw(int argc, const VALUE * argv, int kw_splat) { - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = vm_yield(GET_EC(), argc, argv, kw_splat); - rb_free_tmp_buffer(&v); - return ret; + return vm_yield(GET_EC(), argc, argv, kw_splat); } static inline VALUE @@ -1314,13 +1255,9 @@ rb_yield_force_blockarg(VALUE values) VALUE rb_yield_block(RB_BLOCK_CALL_FUNC_ARGLIST(val, arg)) { - int kw_splat = RB_PASS_CALLED_KEYWORDS; - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); - VALUE ret = vm_yield_with_block(GET_EC(), argc, argv, - NIL_P(blockarg) ? VM_BLOCK_HANDLER_NONE : blockarg, - kw_splat); - rb_free_tmp_buffer(&v); - return ret; + return vm_yield_with_block(GET_EC(), argc, argv, + NIL_P(blockarg) ? VM_BLOCK_HANDLER_NONE : blockarg, + rb_keyword_given_p()); } static VALUE @@ -1486,15 +1423,12 @@ rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE * argv, { struct iter_method_arg arg; - VALUE v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); arg.obj = obj; arg.mid = mid; arg.argc = argc; arg.argv = argv; arg.kw_splat = kw_splat; - VALUE ret = rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2); - rb_free_tmp_buffer(&v); - return ret; + return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2); } VALUE @@ -1839,9 +1773,6 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv, int kw_splat) const VALUE *ep = NULL; rb_cref_t *cref; int is_lambda = FALSE; - VALUE v = 0, ret; - - v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat); if (block_handler != VM_BLOCK_HANDLER_NONE) { again: @@ -1861,10 +1792,9 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv, int kw_splat) block_handler = vm_proc_to_block_handler(VM_BH_TO_PROC(block_handler)); goto again; case block_handler_type_symbol: - ret = rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)), - argc, argv, kw_splat, VM_BLOCK_HANDLER_NONE); - rb_free_tmp_buffer(&v); - return ret; + return rb_sym_proc_call(SYM2ID(VM_BH_TO_SYMBOL(block_handler)), + argc, argv, kw_splat, + VM_BLOCK_HANDLER_NONE); } new_captured.self = self; @@ -1874,9 +1804,7 @@ yield_under(VALUE under, VALUE self, int argc, const VALUE *argv, int kw_splat) } cref = vm_cref_push(ec, under, ep, TRUE); - ret = vm_yield_with_cref(ec, argc, argv, kw_splat, cref, is_lambda); - rb_free_tmp_buffer(&v); - return ret; + return vm_yield_with_cref(ec, argc, argv, kw_splat, cref, is_lambda); } VALUE diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 8cc47e15af..d69340b071 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2486,9 +2486,8 @@ vm_method_cfunc_entry(const rb_callable_method_entry_t *me) return UNALIGNED_MEMBER_PTR(me->def, body.cfunc); } -/* -- Remove empty_kw_splat In 3.0 -- */ static VALUE -vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd, int empty_kw_splat) +vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd) { const struct rb_call_info *ci = &cd->ci; const struct rb_call_cache *cc = &cd->cc; @@ -2506,9 +2505,6 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp if (UNLIKELY(calling->kw_splat)) { frame_type |= VM_FRAME_FLAG_CFRAME_KW; } - else if (UNLIKELY(empty_kw_splat)) { - frame_type |= VM_FRAME_FLAG_CFRAME_EMPTY_KW; - } RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id); EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, ci->mid, me->owner, Qundef); @@ -2536,16 +2532,11 @@ static VALUE vm_call_cfunc(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd) { const struct rb_call_info *ci = &cd->ci; - int empty_kw_splat; RB_DEBUG_COUNTER_INC(ccf_cfunc); CALLER_SETUP_ARG(reg_cfp, calling, ci); - empty_kw_splat = calling->kw_splat; CALLER_REMOVE_EMPTY_KW_SPLAT(reg_cfp, calling, ci); - if (empty_kw_splat && calling->kw_splat) { - empty_kw_splat = 0; - } - return vm_call_cfunc_with_frame(ec, reg_cfp, calling, cd, empty_kw_splat); + return vm_call_cfunc_with_frame(ec, reg_cfp, calling, cd); } static VALUE @@ -2935,12 +2926,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st case VM_METHOD_TYPE_ATTRSET: CALLER_SETUP_ARG(cfp, calling, ci); - if (calling->argc == 1 && calling->kw_splat && RHASH_EMPTY_P(cfp->sp[-1])) { - rb_warn_keyword_to_last_hash(ec, calling, ci, NULL); - } - else { - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); - } + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); rb_check_arity(calling->argc, 1, 1); cc->aux.index = 0; @@ -3211,13 +3197,8 @@ vm_yield_with_cfunc(rb_execution_context_t *ec, blockarg = rb_vm_bh_to_procval(ec, block_handler); frame_flag = VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME | (me ? VM_FRAME_FLAG_BMETHOD : 0); - switch (kw_splat) { - case 1: - frame_flag |= VM_FRAME_FLAG_CFRAME_KW; - break; - case 2: - frame_flag |= VM_FRAME_FLAG_CFRAME_EMPTY_KW; - break; + if (kw_splat) { + frame_flag |= VM_FRAME_FLAG_CFRAME_KW; } vm_push_frame(ec, (const rb_iseq_t *)captured->code.ifunc, @@ -3274,12 +3255,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca VALUE arg0; CALLER_SETUP_ARG(cfp, calling, ci); - if (calling->kw_splat && calling->argc == iseq->body->param.lead_num + iseq->body->param.post_num && RHASH_EMPTY_P(cfp->sp[-1])) { - rb_warn_keyword_to_last_hash(ec, calling, ci, iseq); - } - else { - CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); - } + CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); if (arg_setup_type == arg_setup_block && calling->argc == 1 && @@ -3377,17 +3353,10 @@ vm_invoke_ifunc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, { VALUE val; int argc; - int kw_splat = calling->kw_splat; CALLER_SETUP_ARG(ec->cfp, calling, ci); CALLER_REMOVE_EMPTY_KW_SPLAT(ec->cfp, calling, ci); - if (kw_splat && !calling->kw_splat) { - kw_splat = 2; - } - else { - kw_splat = calling->kw_splat; - } argc = calling->argc; - val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), kw_splat, calling->block_handler, NULL); + val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), calling->kw_splat, calling->block_handler, NULL); POPN(argc); /* TODO: should put before C/yield? */ return val; } -- cgit v1.2.3