ruby-changes:59798
From: Jeremy <ko1@a...>
Date: Sat, 25 Jan 2020 06:04:34 +0900 (JST)
Subject: [ruby-changes:59798] c1d8829ef5 (master): Do not autosplat when calling proc with empty keyword splat
https://git.ruby-lang.org/ruby.git/commit/?id=c1d8829ef5 From c1d8829ef515ee51fadeadd7dd022b5c47a71cdd Mon Sep 17 00:00:00 2001 From: Jeremy Evans <code@j...> Date: Fri, 24 Jan 2020 12:13:41 -0800 Subject: Do not autosplat when calling proc with empty keyword splat With the removal of the splatted argument when using an empty keyword splat, the autosplat code considered an empty keyword splat the same as no argument at all. However, that results in autosplat behavior changing dependent on the content of the splatted hash, which is not what anyone would expect or want. This change always skips an autosplat if keywords were provided. Fixes [Bug #16560] diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index af4cf11..4177707 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -1087,6 +1087,26 @@ class TestProc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_proc.rb#L1087 assert_equal([1,2,[3],4,5], r, "[ruby-core:19485]") end + def test_proc_autosplat + def self.a(arg, kw) + yield arg + yield arg, **kw + yield arg, kw + end + + arr = [] + a([1,2,3], {}) do |arg1, arg2=0| + arr << [arg1, arg2] + end + assert_equal([[1, 2], [[1, 2, 3], 0], [[1, 2, 3], {}]], arr) + + arr = [] + a([1,2,3], a: 1) do |arg1, arg2=0| + arr << [arg1, arg2] + end + assert_equal([[1, 2], [[1, 2, 3], {a: 1}], [[1, 2, 3], {a: 1}]], arr) + end + def test_proc_single_arg_with_keywords_accepted_and_yielded def self.a yield [], **{a: 1} diff --git a/vm_args.c b/vm_args.c index 256ab5b..13d4e4a 100644 --- a/vm_args.c +++ b/vm_args.c @@ -445,9 +445,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co https://github.com/ruby/ruby/blob/trunk/vm_args.c#L445 { const int min_argc = iseq->body->param.lead_num + iseq->body->param.post_num; 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; unsigned int kw_flag = ci->flag & (VM_CALL_KWARG | VM_CALL_KW_SPLAT); + int opt_pc = 0, allow_autosplat = !kw_flag; struct args_info args_body, *args; VALUE keyword_hash = Qnil; VALUE * const orig_sp = ec->cfp->sp; @@ -573,6 +573,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co https://github.com/ruby/ruby/blob/trunk/vm_args.c#L573 break; /* do nothing special */ case arg_setup_block: if (given_argc == (keyword_hash == Qnil ? 1 : 2) && + allow_autosplat && (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 && -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/