From: "jeremyevans0 (Jeremy Evans) via ruby-core" Date: 2024-08-27T14:23:05+00:00 Subject: [ruby-core:118966] [Ruby master Bug#20701] Hash argument passed as keyword splat can be mutated inside method Issue #20701 has been updated by jeremyevans0 (Jeremy Evans). Thanks for the report. Looks like a regression in commit:e87d0882910001ef3b0c2ccd43bf00cee8c34a0c. I submitted a pull request to fix this: https://github.com/ruby/ruby/pull/11468 ---------------------------------------- Bug #20701: Hash argument passed as keyword splat can be mutated inside method https://bugs.ruby-lang.org/issues/20701#change-109536 * Author: pabloh (Pablo Herrero) * Status: Open * ruby -v: ruby 3.4.0dev (2024-08-27T00:39:24Z master e5295644c9) [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- If you call a method with a splatted kwargs that also uses a splatted array followed by at least one positional argument, the called method can mutate the splatted kwargs. ``` ruby def foo(a, h) h[:splat_modified] = true end a = [] b = {splat_modified: false} foo(*a, :x, **b) b[:splat_modified] # Should be 'false' but is 'true' # It makes no difference if the called method expects a kwargs def foo2(a, **h) h[:splat_modified] = true end b[:splat_modified] = false foo2(*a, :x, **b) b[:splat_modified] # Should be 'false' but is 'true' # The case when a block is also pass is broken too c = proc { } b[:splat_modified] = false foo(*a, :x, **b, &c) b[:splat_modified] # Should be 'false' but is 'true' # When the extra positional argument after the array splat is removed the correct behavior is restored b[:splat_modified] = false foo(*a, **b) foo(*a, :x, **b, &c) b[:splat_modified] # Is 'false' ``` Apparently, this problem is due to the `KW_SPLAT_MUT` flag being set at the method's call site: `ruby --dump=insns,-optimize -e 'a, b, c = [4,6,4],{a: 3},:ds; foo(*a,9,**c)` outputs ``` 0000 duparray [4, 6, 4] ( 1)[Li] 0002 duphash {:a=>3} 0004 putobject :ds 0006 setlocal c@2, 0 0009 setlocal b@1, 0 0012 setlocal a@0, 0 0015 putself 0016 getlocal a@0, 0 0019 splatarray true 0021 putobject 9 0023 pushtoarray 1 0025 getlocal c@2, 0 0028 send , nil 0031 leave ``` The error is present in both 3.3 and 3.4: - ruby 3.4.0dev (2024-08-27T00:39:24Z master e5295644c9) [x86_64-linux] - ruby 3.3.4 (2024-07-09 revision be1089c8ec) [x86_64-linux] PR for test: https://github.com/ruby/ruby/pull/11467 -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/