Project

General

Profile

« Previous | Next » 

Revision 07d3bf48

Added by jeremyevans (Jeremy Evans) about 1 year ago

Fix evaluation order issue in f(**h, &h.delete(key))

Previously, this would delete the key in h before keyword
splatting h. This goes against how ruby handles f(*a, &a.pop)
and similar expressions.

Fix this by having the compiler check whether the block pass
expression is safe. If it is not safe, then dup the keyword
splatted hash before evaluating the block pass expression.

For expression: h=nil; f(**h, &h.delete(:key))

VM instructions before:

0000 putnil ( 1)[Li] 0001 setlocal_WC_0 h@0 0003 putself 0004 getlocal_WC_0 h@0 0006 getlocal_WC_0 h@0 0008 putobject :key 0010 opt_send_without_block <calldata!mid:delete, argc:1, ARGS_SIMPLE> 0012 splatkw 0013 send <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT>, nil 0016 leave 

VM instructions after:

0000 putnil ( 1)[Li] 0001 setlocal_WC_0 h@0 0003 putself 0004 putspecialobject 1 0006 newhash 0 0008 getlocal_WC_0 h@0 0010 opt_send_without_block <calldata!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE> 0012 getlocal_WC_0 h@0 0014 putobject :key 0016 opt_send_without_block <calldata!mid:delete, argc:1, ARGS_SIMPLE> 0018 send <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT|KW_SPLAT_MUT>, nil 0021 leave 

Fixes [Bug #20640]