Skip to content

Commit

Permalink
Fix op asgn method calls passing mutable keyword splats
Browse files Browse the repository at this point in the history
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 []=.
  • Loading branch information
jeremyevans committed Dec 14, 2023
1 parent 247ce71 commit a18819e
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
2 changes: 1 addition & 1 deletion compile.c
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions test/ruby/test_call.rb
Expand Up @@ -281,6 +281,27 @@ def o.[]=(...) end
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]
Expand Down

0 comments on commit a18819e

Please sign in to comment.