Fix incorrect use of VM_CALL_KW_SPLAT_MUT in zsuper with keyword splat
For zsuper calls with a keyword splat but no actual keywords, the keyword splat is passed directly, so it cannot be mutable, because if the callee accepts a keyword splat, changes to the keyword splat by the callee would be reflected in the caller. While here, simplify the logic when the method supports literal keywords. I don't think it is possible for a method with has_kw param flags to not have keywords, so add an assertion for that, and set VM_CALL_KW_SPLAT_MUT in a single place.
This commit is contained in:
parent
395a240b7c
commit
771a2f039b
@ -9534,14 +9534,11 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
|
|||||||
if (local_body->param.flags.has_kwrest) {
|
if (local_body->param.flags.has_kwrest) {
|
||||||
int idx = local_body->local_table_size - local_kwd->rest_start;
|
int idx = local_body->local_table_size - local_kwd->rest_start;
|
||||||
ADD_GETLOCAL(args, node, idx, lvar_level);
|
ADD_GETLOCAL(args, node, idx, lvar_level);
|
||||||
if (local_kwd->num > 0) {
|
assert(local_kwd->num > 0);
|
||||||
ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
|
ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
|
||||||
flag |= VM_CALL_KW_SPLAT_MUT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ADD_INSN1(args, node, newhash, INT2FIX(0));
|
ADD_INSN1(args, node, newhash, INT2FIX(0));
|
||||||
flag |= VM_CALL_KW_SPLAT_MUT;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < local_kwd->num; ++i) {
|
for (i = 0; i < local_kwd->num; ++i) {
|
||||||
ID id = local_kwd->table[i];
|
ID id = local_kwd->table[i];
|
||||||
@ -9550,13 +9547,13 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
|
|||||||
ADD_GETLOCAL(args, node, idx, lvar_level);
|
ADD_GETLOCAL(args, node, idx, lvar_level);
|
||||||
}
|
}
|
||||||
ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
|
ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
|
||||||
flag |= VM_CALL_KW_SPLAT;
|
flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
|
||||||
}
|
}
|
||||||
else if (local_body->param.flags.has_kwrest) {
|
else if (local_body->param.flags.has_kwrest) {
|
||||||
int idx = local_body->local_table_size - local_kwd->rest_start;
|
int idx = local_body->local_table_size - local_kwd->rest_start;
|
||||||
ADD_GETLOCAL(args, node, idx, lvar_level);
|
ADD_GETLOCAL(args, node, idx, lvar_level);
|
||||||
argc++;
|
argc++;
|
||||||
flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
|
flag |= VM_CALL_KW_SPLAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,6 +558,18 @@ class TestSuper < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_zsuper_kw_splat_not_mutable
|
||||||
|
extend(Module.new{def a(**k) k[:a] = 1 end})
|
||||||
|
extend(Module.new do
|
||||||
|
def a(**k)
|
||||||
|
before = k.dup
|
||||||
|
super
|
||||||
|
[before, k]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
assert_equal(*a)
|
||||||
|
end
|
||||||
|
|
||||||
def test_from_eval
|
def test_from_eval
|
||||||
bug10263 = '[ruby-core:65122] [Bug #10263a]'
|
bug10263 = '[ruby-core:65122] [Bug #10263a]'
|
||||||
a = Class.new do
|
a = Class.new do
|
||||||
|
Loading…
x
Reference in New Issue
Block a user