mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Do not autosplat array in block call just because keywords accepted
If the block only accepts a single positional argument plus keywords, then do not autosplat. Still autosplat if the block accepts more than one positional argument in addition to keywords. Autosplatting a single positional argument plus keywords made sense in Ruby 2, since a final positional hash could be used as keywords, but it does not make sense in Ruby 3. Fixes [Bug #18633]
This commit is contained in:
parent
75efbb98af
commit
fbaadd1cfe
Notes:
git
2022-03-31 03:04:30 +09:00
Merged: https://github.com/ruby/ruby/pull/5665 Merged-By: jeremyevans <code@jeremyevans.net>
4 changed files with 97 additions and 4 deletions
|
@ -40,8 +40,17 @@ describe "A block yielded a single" do
|
|||
m([1, 2]) { |a=5, b, c, d| [a, b, c, d] }.should == [5, 1, 2, nil]
|
||||
end
|
||||
|
||||
it "assigns elements to required arguments when a keyword rest argument is present" do
|
||||
m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
|
||||
ruby_version_is "3.2" do
|
||||
it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
|
||||
m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ''..."3.2" do
|
||||
# https://bugs.ruby-lang.org/issues/18633
|
||||
it "autosplats single argument to required arguments when a keyword rest argument is present" do
|
||||
m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is ''..."3.0" do
|
||||
|
|
|
@ -3538,7 +3538,7 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||
assert_equal(splat_expect, pr.call(a), bug8463)
|
||||
|
||||
pr = proc {|a, **opt| next a, opt}
|
||||
assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463)
|
||||
assert_equal([splat_expect, {}], pr.call(splat_expect), bug8463)
|
||||
end
|
||||
|
||||
def req_plus_keyword(x, **h)
|
||||
|
|
|
@ -857,6 +857,88 @@ class TestProc < Test::Unit::TestCase
|
|||
assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x})
|
||||
end
|
||||
|
||||
def test_proc_args_single_kw_no_autosplat
|
||||
pr = proc {|c, a: 1| [c, a] }
|
||||
assert_equal [nil, 1], pr.call()
|
||||
assert_equal [1, 1], pr.call(1)
|
||||
assert_equal [[1], 1], pr.call([1])
|
||||
assert_equal [1, 1], pr.call(1,2)
|
||||
assert_equal [[1, 2], 1], pr.call([1,2])
|
||||
|
||||
assert_equal [nil, 3], pr.call(a: 3)
|
||||
assert_equal [1, 3], pr.call(1, a: 3)
|
||||
assert_equal [[1], 3], pr.call([1], a: 3)
|
||||
assert_equal [1, 3], pr.call(1,2, a: 3)
|
||||
assert_equal [[1, 2], 3], pr.call([1,2], a: 3)
|
||||
end
|
||||
|
||||
def test_proc_args_single_kwsplat_no_autosplat
|
||||
pr = proc {|c, **kw| [c, kw] }
|
||||
assert_equal [nil, {}], pr.call()
|
||||
assert_equal [1, {}], pr.call(1)
|
||||
assert_equal [[1], {}], pr.call([1])
|
||||
assert_equal [1, {}], pr.call(1,2)
|
||||
assert_equal [[1, 2], {}], pr.call([1,2])
|
||||
|
||||
assert_equal [nil, {a: 3}], pr.call(a: 3)
|
||||
assert_equal [1, {a: 3}], pr.call(1, a: 3)
|
||||
assert_equal [[1], {a: 3}], pr.call([1], a: 3)
|
||||
assert_equal [1, {a: 3}], pr.call(1,2, a: 3)
|
||||
assert_equal [[1, 2], {a: 3}], pr.call([1,2], a: 3)
|
||||
end
|
||||
|
||||
def test_proc_args_multiple_kw_autosplat
|
||||
pr = proc {|c, b, a: 1| [c, b, a] }
|
||||
assert_equal [1, 2, 1], pr.call([1,2])
|
||||
|
||||
pr = proc {|c=nil, b=nil, a: 1| [c, b, a] }
|
||||
assert_equal [nil, nil, 1], pr.call([])
|
||||
assert_equal [1, nil, 1], pr.call([1])
|
||||
assert_equal [1, 2, 1], pr.call([1,2])
|
||||
|
||||
pr = proc {|c, b=nil, a: 1| [c, b, a] }
|
||||
assert_equal [1, nil, 1], pr.call([1])
|
||||
assert_equal [1, 2, 1], pr.call([1,2])
|
||||
|
||||
pr = proc {|c=nil, b, a: 1| [c, b, a] }
|
||||
assert_equal [nil, 1, 1], pr.call([1])
|
||||
assert_equal [1, 2, 1], pr.call([1,2])
|
||||
|
||||
pr = proc {|c, *b, a: 1| [c, b, a] }
|
||||
assert_equal [1, [], 1], pr.call([1])
|
||||
assert_equal [1, [2], 1], pr.call([1,2])
|
||||
|
||||
pr = proc {|*c, b, a: 1| [c, b, a] }
|
||||
assert_equal [[], 1, 1], pr.call([1])
|
||||
assert_equal [[1], 2, 1], pr.call([1,2])
|
||||
end
|
||||
|
||||
def test_proc_args_multiple_kwsplat_autosplat
|
||||
pr = proc {|c, b, **kw| [c, b, kw] }
|
||||
assert_equal [1, 2, {}], pr.call([1,2])
|
||||
|
||||
pr = proc {|c=nil, b=nil, **kw| [c, b, kw] }
|
||||
assert_equal [nil, nil, {}], pr.call([])
|
||||
assert_equal [1, nil, {}], pr.call([1])
|
||||
assert_equal [1, 2, {}], pr.call([1,2])
|
||||
|
||||
pr = proc {|c, b=nil, **kw| [c, b, kw] }
|
||||
assert_equal [1, nil, {}], pr.call([1])
|
||||
assert_equal [1, 2, {}], pr.call([1,2])
|
||||
|
||||
pr = proc {|c=nil, b, **kw| [c, b, kw] }
|
||||
assert_equal [nil, 1, {}], pr.call([1])
|
||||
assert_equal [1, 2, {}], pr.call([1,2])
|
||||
|
||||
pr = proc {|c, *b, **kw| [c, b, kw] }
|
||||
assert_equal [1, [], {}], pr.call([1])
|
||||
assert_equal [1, [2], {}], pr.call([1,2])
|
||||
|
||||
pr = proc {|*c, b, **kw| [c, b, kw] }
|
||||
assert_equal [[], 1, {}], pr.call([1])
|
||||
assert_equal [[1], 2, {}], pr.call([1,2])
|
||||
end
|
||||
|
||||
def test_proc_args_only_rest
|
||||
pr = proc {|*c| c }
|
||||
assert_equal [], pr.call()
|
||||
|
|
|
@ -599,7 +599,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
rb_raise(rb_eArgError, "no keywords accepted");
|
||||
}
|
||||
|
||||
|
||||
switch (arg_setup_type) {
|
||||
case arg_setup_method:
|
||||
break; /* do nothing special */
|
||||
|
@ -608,6 +607,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||
allow_autosplat &&
|
||||
(min_argc > 0 || ISEQ_BODY(iseq)->param.opt_num > 1) &&
|
||||
!ISEQ_BODY(iseq)->param.flags.ambiguous_param0 &&
|
||||
!((ISEQ_BODY(iseq)->param.flags.has_kw ||
|
||||
ISEQ_BODY(iseq)->param.flags.has_kwrest)
|
||||
&& max_argc == 1) &&
|
||||
args_check_block_arg0(args)) {
|
||||
given_argc = RARRAY_LENINT(args->rest);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue