diff options
author | Jeremy Evans <code@jeremyevans.net> | 2023-11-08 15:56:53 -0800 |
---|---|---|
committer | Jeremy Evans <code@jeremyevans.net> | 2023-12-09 13:15:47 -0800 |
commit | a950f230788d51e13d16596e37cb77e4cc6e2311 (patch) | |
tree | 0110843746e7703e38e660dbe52da776656eade7 /test/ruby/test_call.rb | |
parent | c0b6ea7c8b5dc6e48ecf6e14e1dbd135d079f0fc (diff) |
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.
Diffstat (limited to 'test/ruby/test_call.rb')
-rw-r--r-- | test/ruby/test_call.rb | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/test/ruby/test_call.rb b/test/ruby/test_call.rb index 67a94ed7af..d009691fd0 100644 --- a/test/ruby/test_call.rb +++ b/test/ruby/test_call.rb @@ -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 |