mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
YJIT: Fix defined?(yield)
and block_given?
at top level
Previously, YJIT returned truthy for the block given query at the top level. That's incorrect because the top level script never receives a block, and `yield` is a syntax error there. Inside methods, the number of hops to get from `iseq` to `iseq->body->local_iseq` is the same as the number of `VM_ENV_PREV_EP(ep)` hops to get to an environment with `VM_ENV_FLAG_LOCAL`. YJIT and the interpreter both rely on this as can be seen in get_lvar_level(). However, this identity does not hold for the top level frame because of vm_set_eval_stack(), which sets up `TOPLEVEL_BINDING`. Since only methods can take a block that `yield` goes to, have ISEQs that are the child of a non-method ISEQ return falsy for the block given query. This fixes the issue for the top level script and is an optimization for non-method contexts such as inside `ISEQ_TYPE_CLASS`.
This commit is contained in:
parent
b080fcd3cd
commit
38558dd95e
2 changed files with 44 additions and 9 deletions
|
@ -5342,3 +5342,30 @@ assert_equal 'nil', %{
|
|||
|
||||
test_local_fill_in_forwardable.inspect
|
||||
}
|
||||
|
||||
# Test defined?(yield) and block_given? in non-method context.
|
||||
# It's good that the body of this runs at true top level and isn't wrapped in a block.
|
||||
assert_equal 'false', %{
|
||||
RESULT = []
|
||||
RESULT << defined?(yield)
|
||||
RESULT << block_given?
|
||||
|
||||
1.times do
|
||||
RESULT << defined?(yield)
|
||||
RESULT << block_given?
|
||||
end
|
||||
|
||||
module ModuleContext
|
||||
1.times do
|
||||
RESULT << defined?(yield)
|
||||
RESULT << block_given?
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
RESULT << defined?(yield)
|
||||
RESULT << block_given?
|
||||
end
|
||||
|
||||
RESULT.any?
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue