mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Fix ensure with yield context on break and return
How to reproduce:
class A
def x
yield
ensure
y
end
def y
end
end
# Work
A.new.x do
end
# Not work
# trace:
# [2] /tmp/a.rb:5:in A.x
# [0] /tmp/a.rb:15
# /tmp/a.rb:5: undefined method 'y' for main (NoMethodError)
A.new.x do
break
end
# trace:
# [2] /tmp/a.rb:5:in A.call
# [0] /tmp/a.rb:19
# /tmp/a.rb:5: undefined method 'y' for main (NoMethodError)
lambda do
A.new.x do
return
end
end.call
`self` in ensure is broken when yield and break/return are used.
This commit is contained in:
@@ -1514,6 +1514,7 @@ RETRY_TRY_BLOCK:
|
||||
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
|
||||
goto L_RAISE;
|
||||
}
|
||||
mrb->c->stack = mrb->c->ci->stackent;
|
||||
mrb->c->ci = ci;
|
||||
break;
|
||||
}
|
||||
@@ -1548,6 +1549,7 @@ RETRY_TRY_BLOCK:
|
||||
c->prev = NULL;
|
||||
}
|
||||
ci = mrb->c->ci;
|
||||
mrb->c->stack = ci->stackent;
|
||||
mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
|
||||
while (ci > mrb->c->ci) {
|
||||
if (ci[-1].acc == CI_ACC_SKIP) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
##
|
||||
# ensure Test
|
||||
|
||||
assert('ensure - context - yield') do
|
||||
class EnsureYieldBreak
|
||||
attr_reader :ensure_context
|
||||
def try
|
||||
yield
|
||||
ensure
|
||||
@ensure_context = self
|
||||
end
|
||||
end
|
||||
|
||||
yielder = EnsureYieldBreak.new
|
||||
yielder.try do
|
||||
end
|
||||
assert_equal yielder, yielder.ensure_context
|
||||
end
|
||||
|
||||
assert('ensure - context - yield and break') do
|
||||
class EnsureYieldBreak
|
||||
attr_reader :ensure_context
|
||||
def try
|
||||
yield
|
||||
ensure
|
||||
@ensure_context = self
|
||||
end
|
||||
end
|
||||
|
||||
yielder = EnsureYieldBreak.new
|
||||
yielder.try do
|
||||
break
|
||||
end
|
||||
assert_equal yielder, yielder.ensure_context
|
||||
end
|
||||
|
||||
assert('ensure - context - yield and return') do
|
||||
class EnsureYieldBreak
|
||||
attr_reader :ensure_context
|
||||
def try
|
||||
yield
|
||||
ensure
|
||||
@ensure_context = self
|
||||
end
|
||||
end
|
||||
|
||||
yielder = EnsureYieldBreak.new
|
||||
lambda do
|
||||
yielder.try do
|
||||
return
|
||||
end
|
||||
end.call
|
||||
assert_equal yielder, yielder.ensure_context
|
||||
end
|
||||
Reference in New Issue
Block a user