mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 15:06:10 +02:00
Ensure f(**kw, &block) calls kw.to_hash before block.to_proc
Previously, block.to_proc was called first, by vm_caller_setup_arg_block. kw.to_hash was called later inside CALLER_SETUP_ARG or setup_parameters_complex. This adds a splatkw instruction that is inserted before sends with ARGS_BLOCKARG and KW_SPLAT and without KW_SPLAT_MUT. This is not needed in the KW_SPLAT_MUT case, because then you know the value is a hash, and you don't need to call to_hash on it. The splatkw instruction checks whether the second to top block is a hash, and if not, replaces it with the value of calling to_hash on it (using rb_to_hash_type). As it is always before a send with ARGS_BLOCKARG and KW_SPLAT, second to top is the keyword splat, and top is the passed block.
This commit is contained in:
parent
c0b6ea7c8b
commit
a950f23078
4 changed files with 203 additions and 170 deletions
|
@ -147,6 +147,23 @@ class TestCall < Test::Unit::TestCase
|
|||
assert_equal Hash, f(*[], **o).class
|
||||
end
|
||||
|
||||
def test_kwsplat_block_order
|
||||
o = Object.new
|
||||
ary = []
|
||||
o.define_singleton_method(:to_a) {ary << :to_a; []}
|
||||
o.define_singleton_method(:to_hash) {ary << :to_hash; {}}
|
||||
o.define_singleton_method(:to_proc) {ary << :to_proc; lambda{}}
|
||||
|
||||
def self.t(...) end
|
||||
|
||||
t(**o, &o)
|
||||
assert_equal([:to_hash, :to_proc], ary)
|
||||
|
||||
ary.clear
|
||||
t(*o, **o, &o)
|
||||
assert_equal([:to_a, :to_hash, :to_proc], ary)
|
||||
end
|
||||
|
||||
OVER_STACK_LEN = (ENV['RUBY_OVER_STACK_LEN'] || 150).to_i # Greater than VM_ARGC_STACK_MAX
|
||||
OVER_STACK_ARGV = OVER_STACK_LEN.times.to_a.freeze
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue