Bug #20051
closedOp asgn calls handle keywords and keyword splats as positional arguments
Description
Ruby passes a keywords given to op asgn method calls as a positional hash argument, both to []
and []=
:
foo[kw: 1] += bar
This seems wrong, because foo[kw: 1]
passes kw: 1
as keywords.
Worse, Ruby passes a keyword splat given to the op asgn method calls as a regular positional argument to []
and []=
, with no to_hash
conversion:
foo[**kw] += bar
Example:
[1][**0] += 2
# => 3
I'll try to fix this before the 3.3 release if I have time, but if anyone else wants to work on a fix, please do so.
Updated by jeremyevans0 (Jeremy Evans) 11 months ago
- Related to Bug #20008: f(**kw, &block) calls block.to_proc before kw.to_hash added
Updated by jeremyevans0 (Jeremy Evans) 11 months ago
Looks like I was testing on Ruby 3.2, not on master. The current master branch has even worse behavior for keywords. The following code segfaults in the compiler (--dump=parse
works, --dump=i
segfaults):
Object[kw: 1] += 1
Code with keyword splats results in a TypeError:
h = Object.new
def h.[](*a, **b) p [:[], a, b]; 3 end
def h.[]=(*a, **b) p [:[]=, a, b]; nil end
kw = Object.new
def kw.to_hash; p [:to_hash]; {4=>5} end
h[**kw] += 1
In Ruby 3.2:
[:[], [#<Object:0x00000ce0f9c44c80>], {}]
[:[]=, [#<Object:0x00000ce0f9c44c80>, 4], {}]
In Ruby 3.3-preview3:
[:to_hash]
[:[], [], {4=>5}]
t/t99.rb:8:in `<main>': no implicit conversion of Integer into Hash (TypeError)
h[**kw] += 1
^^^^^^^^^^
Updated by jeremyevans0 (Jeremy Evans) 11 months ago
I submitted a pull request to fix this issue: https://github.com/ruby/ruby/pull/9172
Updated by jeremyevans (Jeremy Evans) 11 months ago
- Status changed from Open to Closed
Applied in changeset git|2f1d6da8c45590bf3461ed4bf051a4e1009eaf85.
Fix op asgn calls with keywords
Examples of such calls:
obj[kw: 1] += fo
obj[**kw] &&= bar
Before this patch, literal keywords would segfault in the compiler,
and keyword splat usage would result in TypeError.
This handles all cases I can think of:
- literal keywords
- keyword splats
- combined with positional arguments
- combined with regular splats
- both with and without blocks
- both popped and non-popped cases
This also makes sure that to_hash is only called once on the keyword
splat argument, instead of twice, and make sure it is called before
calling to_proc on a passed block.
Fixes [Bug #20051]
Co-authored-by: Nobuyoshi Nakada nobu@ruby-lang.org