summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c3
-rw-r--r--test/ruby/test_keyword.rb7
-rw-r--r--vm_args.c11
-rw-r--r--yjit/src/codegen.rs2
4 files changed, 16 insertions, 7 deletions
diff --git a/compile.c b/compile.c
index 7f090b6748..f1dd595e3d 100644
--- a/compile.c
+++ b/compile.c
@@ -1976,8 +1976,11 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
keyword->num = kw;
if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
+ ID kw_id = iseq->body->local_table[arg_size];
keyword->rest_start = arg_size++;
body->param.flags.has_kwrest = TRUE;
+
+ if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
}
keyword->required_num = rkw;
keyword->table = &body->local_table[keyword->bits_start - keyword->num];
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index a856a46569..5d0262a449 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -182,6 +182,13 @@ class TestKeywordArguments < Test::Unit::TestCase
[:keyrest, :kw], [:block, :b]], method(:f9).parameters)
end
+ def test_keyword_with_anonymous_keyword_splat
+ def self.a(b: 1, **) [b, **] end
+ kw = {b: 2, c: 3}
+ assert_equal([2, {c: 3}], a(**kw))
+ assert_equal({b: 2, c: 3}, kw)
+ end
+
def test_keyword_splat_nil
# cfunc call
assert_equal(nil, p(**nil))
diff --git a/vm_args.c b/vm_args.c
index a9c391f273..ec5df37aab 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -504,6 +504,11 @@ ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq, unsigned
if (!RB_TYPE_P(keyword_hash, T_HASH)) {
keyword_hash = rb_to_hash_type(keyword_hash);
}
+ else if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.anon_kwrest)) {
+ if (!ISEQ_BODY(iseq)->param.flags.has_kw) {
+ *kw_flag |= VM_CALL_KW_SPLAT_MUT;
+ }
+ }
if (!(*kw_flag & VM_CALL_KW_SPLAT_MUT) &&
(ISEQ_BODY(iseq)->param.flags.has_kwrest ||
@@ -590,12 +595,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
}
}
- if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.anon_kwrest)) {
- if (kw_flag & VM_CALL_KW_SPLAT) {
- kw_flag |= VM_CALL_KW_SPLAT_MUT;
- }
- }
-
if (kw_flag & VM_CALL_KWARG) {
args->kw_arg = vm_ci_kwarg(ci);
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index c150d48666..41a8cdebca 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -7510,7 +7510,7 @@ fn gen_iseq_kw_call(
unsafe { get_cikw_keyword_len(ci_kwarg) }
};
let caller_keyword_len: usize = caller_keyword_len_i32.try_into().unwrap();
- let anon_kwrest = unsafe { rb_get_iseq_flags_anon_kwrest(iseq) };
+ let anon_kwrest = unsafe { rb_get_iseq_flags_anon_kwrest(iseq) && !get_iseq_flags_has_kw(iseq) };
// This struct represents the metadata about the callee-specified
// keyword parameters.