summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/ruby/language/block_spec.rb31
-rw-r--r--test/ruby/test_keyword.rb19
-rw-r--r--test/ruby/test_proc.rb27
-rw-r--r--vm_args.c4
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)]
diff --git a/vm_args.c b/vm_args.c
index e6d4981b33..50bb02311d 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -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);