diff options
-rw-r--r-- | spec/ruby/language/block_spec.rb | 31 | ||||
-rw-r--r-- | test/ruby/test_keyword.rb | 19 | ||||
-rw-r--r-- | test/ruby/test_proc.rb | 27 | ||||
-rw-r--r-- | vm_args.c | 4 |
4 files changed, 61 insertions, 20 deletions
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index 1a8e79063d..99366006b0 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -76,18 +76,18 @@ describe "A block yielded a single" do result.should == [1, 2, [3], {x: 9}, 2, {}] end - it "does not treat final Hash as keyword arguments" do + it "does not treat final Hash as keyword arguments and does not autosplat" do result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] } - result.should == [{"a" => 1, a: 10}, {}] + result.should == [[{"a" => 1, a: 10}], {}] end - it "does not call #to_hash on final argument to get keyword arguments" do + it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do suppress_keyword_warning do obj = mock("coerce block keyword arguments") obj.should_not_receive(:to_hash) result = m([obj]) { |a=nil, **b| [a, b] } - result.should == [obj, {}] + result.should == [[obj], {}] end end end @@ -113,12 +113,12 @@ describe "A block yielded a single" do end ruby_version_is "2.8" do - it "does not call #to_hash on the argument when optional argument and keyword argument accepted" do + it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do obj = mock("coerce block keyword arguments") obj.should_not_receive(:to_hash) result = m([obj]) { |a=nil, **b| [a, b] } - result.should == [obj, {}] + result.should == [[obj], {}] end end @@ -132,18 +132,27 @@ describe "A block yielded a single" do end end ruby_version_is "2.8" do - it "does not separates non-symbol keys and symbol keys" do + it "does not separate non-symbol keys and symbol keys and does not autosplat" do suppress_keyword_warning do result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] } - result.should == [{"a" => 10, b: 2}, {}] + result.should == [[{"a" => 10, b: 2}], {}] end end end end - it "does not treat hashes with string keys as keyword arguments" do - result = m(["a" => 10]) { |a = nil, **b| [a, b] } - result.should == [{"a" => 10}, {}] + ruby_version_is ""..."2.8" do + it "does not treat hashes with string keys as keyword arguments" do + result = m(["a" => 10]) { |a = nil, **b| [a, b] } + result.should == [{"a" => 10}, {}] + end + end + + ruby_version_is "2.8" do + it "does not treat hashes with string keys as keyword arguments and does not autosplat" do + result = m(["a" => 10]) { |a = nil, **b| [a, b] } + result.should == [[{"a" => 10}], {}] + end end ruby_version_is ''...'2.8' do diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index db7d696644..48d6a7336a 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -3284,15 +3284,20 @@ class TestKeywordArguments < Test::Unit::TestCase bug7665 = '[ruby-core:51278]' bug8463 = '[ruby-core:55203] [Bug #8463]' a = [*%w[foo bar], {zzz: 42}] - expect = a + [{}] - assert_equal(expect, rest_keyrest(*a), bug7665) + splat_expect = a + [{}] + nonsplat_expect = [a, {}] + assert_equal(splat_expect, rest_keyrest(*a), bug7665) + assert_equal(nonsplat_expect, rest_keyrest(a), bug7665) + pr = proc {|*args, **opt| next *args, opt} - assert_equal(expect, pr.call(*a), bug7665) - assert_equal(expect, pr.call(a), bug8463) + assert_equal(splat_expect, pr.call(*a), bug7665) + assert_equal(nonsplat_expect, pr.call(a), bug8463) + pr = proc {|a, *b, **opt| next a, *b, opt} - assert_equal(expect, pr.call(a), bug8463) + assert_equal(splat_expect, pr.call(a), bug8463) + pr = proc {|a, **opt| next a, opt} - assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463) + assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463) end def req_plus_keyword(x, **h) @@ -3662,7 +3667,7 @@ class TestKeywordArguments < Test::Unit::TestCase def test_nonsymbol_key result = m(["a" => 10]) { |a = nil, **b| [a, b] } - assert_equal([{"a" => 10}, {}], result) + assert_equal([[{"a" => 10}], {}], result) end def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index b00f42d81a..14b79380e2 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -784,6 +784,33 @@ class TestProc < Test::Unit::TestCase assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x}) end + def test_proc_args_only_rest + pr = proc {|*c| c } + assert_equal [], pr.call() + assert_equal [1], pr.call(1) + assert_equal [[1]], pr.call([1]) + assert_equal [1, 2], pr.call(1,2) + assert_equal [[1, 2]], pr.call([1,2]) + end + + def test_proc_args_rest_kw + pr = proc {|*c, a: 1| [c, a] } + assert_equal [[], 1], pr.call() + assert_equal [[1], 1], pr.call(1) + assert_equal [[[1]], 1], pr.call([1]) + assert_equal [[1, 2], 1], pr.call(1,2) + assert_equal [[[1, 2]], 1], pr.call([1,2]) + end + + def test_proc_args_rest_kwsplat + pr = proc {|*c, **kw| [c, kw] } + assert_equal [[], {}], pr.call() + assert_equal [[1], {}], pr.call(1) + assert_equal [[[1]], {}], pr.call([1]) + assert_equal [[1, 2], {}], pr.call(1,2) + assert_equal [[[1, 2]], {}], pr.call([1,2]) + end + def test_proc_args_pos_rest_post_block pr = proc {|a,b,*c,d,e,&f| [a, b, c, d, e, f.class, f&&f.call(:x)] @@ -568,14 +568,14 @@ 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 */ 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) && + (min_argc > 0 || iseq->body->param.opt_num > 1) && !iseq->body->param.flags.ambiguous_param0 && args_check_block_arg0(args)) { given_argc = RARRAY_LENINT(args->rest); |