Skip to content
  • Jeremy Evans's avatar
    29f2cb83
    Fix evaluation order issue in f(**h, &h.delete(key)) · 29f2cb83
    Jeremy Evans authored
    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
    ```
    
    This is the same as 07d3bf48, except that
    it removes unnecessary hash allocations when using the prism compiler.
    
    Fixes [Bug #20640]
    29f2cb83
    Fix evaluation order issue in f(**h, &h.delete(key))
    Jeremy Evans authored
    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
    ```
    
    This is the same as 07d3bf48, except that
    it removes unnecessary hash allocations when using the prism compiler.
    
    Fixes [Bug #20640]
Loading