Do not apply anon_rest optimization when passed array uses keyword-flagged hash

The optimization sets args->rest_dupped to avoid allocating an array,
but this is not safe if the splat array ends in a keyword flagged
hash.  Unset args->rest_dupped in this case.

Fixes [Bug #20388]
This commit is contained in:
Jeremy Evans 2024-03-22 15:29:13 -07:00 коммит произвёл Aaron Patterson
Родитель a2ac28d8ab
Коммит 2dbcc123f4
2 изменённых файлов: 16 добавлений и 0 удалений

Просмотреть файл

@ -2835,6 +2835,19 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal({a: 1}, kw)
end
def test_anon_splat_ruby2_keywords_bug_20388
extend(Module.new{def process(action, ...) 1 end})
extend(Module.new do
def process(action, *args)
args.freeze
super
end
ruby2_keywords :process
end)
assert_equal(1, process(:foo, bar: :baz))
end
def test_top_ruby2_keywords
assert_in_out_err([], <<-INPUT, ["[1, 2, 3]", "{:k=>1}"], [])
def bar(*a, **kw)

Просмотреть файл

@ -687,6 +687,9 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
rest_last = rb_hash_dup(rest_last);
kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
// Unset rest_dupped set by anon_rest as we may need to modify splat in this case
args->rest_dupped = false;
if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) {
arg_rest_dup(args);
rb_ary_pop(args->rest);