Skip to content

Commit 29dafa5

Browse files
jeremyevansbyroot
andcommitted
Fix assertion failure with anonymous splats
When calling a method that accepts an anonymous splat and literal keywords without any arguments, an assertion failure was previously raised. Set rest_index to 0 when setting rest to the frozen hash, so the args_argc calculation is accurate. While here, add more tests for methods with anonymous splats with and without keywords and keyword splats to confirm behavior is correct. Also add a basic bootstrap test that would hit the previous assertion failure. Co-authored-by: Jean Boussier <[email protected]>
1 parent b8e2bec commit 29dafa5

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

bootstraptest/test_method.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,3 +1419,11 @@ def internal_foo = foo
14191419
"ok"
14201420
end
14211421
}
1422+
1423+
assert_equal 'ok', <<~RUBY
1424+
def test(*, kw: false)
1425+
"ok"
1426+
end
1427+
1428+
test
1429+
RUBY

test/ruby/test_call.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,55 @@ def o.foo(a, **h)= h[:splat_modified] = true
374374
assert_equal({splat_modified: false}, b)
375375
end
376376

377+
def test_anon_splat
378+
r2kh = Hash.ruby2_keywords_hash(kw: 2)
379+
r2kea = [r2kh]
380+
r2ka = [1, r2kh]
381+
382+
def self.s(*) ->(*a){a}.call(*) end
383+
assert_equal([], s)
384+
assert_equal([1], s(1))
385+
assert_equal([{kw: 2}], s(kw: 2))
386+
assert_equal([{kw: 2}], s(**{kw: 2}))
387+
assert_equal([1, {kw: 2}], s(1, kw: 2))
388+
assert_equal([1, {kw: 2}], s(1, **{kw: 2}))
389+
assert_equal([{kw: 2}], s(*r2kea))
390+
assert_equal([1, {kw: 2}], s(*r2ka))
391+
392+
singleton_class.remove_method(:s)
393+
def self.s(*, kw: 0) [*->(*a){a}.call(*), kw] end
394+
assert_equal([0], s)
395+
assert_equal([1, 0], s(1))
396+
assert_equal([2], s(kw: 2))
397+
assert_equal([2], s(**{kw: 2}))
398+
assert_equal([1, 2], s(1, kw: 2))
399+
assert_equal([1, 2], s(1, **{kw: 2}))
400+
assert_equal([2], s(*r2kea))
401+
assert_equal([1, 2], s(*r2ka))
402+
403+
singleton_class.remove_method(:s)
404+
def self.s(*, **kw) [*->(*a){a}.call(*), kw] end
405+
assert_equal([{}], s)
406+
assert_equal([1, {}], s(1))
407+
assert_equal([{kw: 2}], s(kw: 2))
408+
assert_equal([{kw: 2}], s(**{kw: 2}))
409+
assert_equal([1, {kw: 2}], s(1, kw: 2))
410+
assert_equal([1, {kw: 2}], s(1, **{kw: 2}))
411+
assert_equal([{kw: 2}], s(*r2kea))
412+
assert_equal([1, {kw: 2}], s(*r2ka))
413+
414+
singleton_class.remove_method(:s)
415+
def self.s(*, kw: 0, **kws) [*->(*a){a}.call(*), kw, kws] end
416+
assert_equal([0, {}], s)
417+
assert_equal([1, 0, {}], s(1))
418+
assert_equal([2, {}], s(kw: 2))
419+
assert_equal([2, {}], s(**{kw: 2}))
420+
assert_equal([1, 2, {}], s(1, kw: 2))
421+
assert_equal([1, 2, {}], s(1, **{kw: 2}))
422+
assert_equal([2, {}], s(*r2kea))
423+
assert_equal([1, 2, {}], s(*r2ka))
424+
end
425+
377426
def test_kwsplat_block_eval_order
378427
def self.t(**kw, &b) [kw, b] end
379428

vm_args.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
896896
if (ISEQ_BODY(iseq)->param.flags.has_rest) {
897897
if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.anon_rest && args->argc == 0 && !args->rest && !ISEQ_BODY(iseq)->param.flags.has_post)) {
898898
*(locals + ISEQ_BODY(iseq)->param.rest_start) = args->rest = rb_cArray_empty_frozen;
899+
args->rest_index = 0;
899900
}
900901
else {
901902
args_setup_rest_parameter(args, locals + ISEQ_BODY(iseq)->param.rest_start);

0 commit comments

Comments
 (0)