Fix op asgn method calls passing mutable keyword splats

When passing the keyword splat to [], it cannot be mutable, because
mutating the keyword splat inside [] would result in changes to the
keyword splat passed to []=.
This commit is contained in:
Jeremy Evans 2023-12-12 16:48:26 -08:00
parent 247ce712fc
commit a18819e65f
2 changed files with 22 additions and 1 deletions

View File

@ -8908,7 +8908,7 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
}
ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
flag |= asgnflag;
ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag), keywords);
ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_KW_SPLAT_MUT), keywords);
if (id == idOROP || id == idANDOP) {
/* a[x] ||= y or a[x] &&= y

View File

@ -281,6 +281,27 @@ class TestCall < Test::Unit::TestCase
assert_equal([:to_a, :to_hash, :to_proc, :to_proc], ary)
end
def test_call_op_asgn_keywords_mutable
h = Class.new do
attr_reader :get, :set
def v; yield; [*@get, *@set] end
def [](*a, **b, &c)
@get = [a.dup, b.dup]
a << :splat_modified
b[:kw_splat_modified] = true
@set = []
3
end
def []=(*a, **b) @set = [a, b] end
end.new
a = []
kw = {}
b = lambda{}
assert_equal([[2], {b: 5}, [2, 4], {b: 5}], h.v{h[*a, 2, b: 5, **kw] += 1})
end
def test_call_splat_order
bug12860 = '[ruby-core:77701] [Bug# 12860]'
ary = [1, 2]