Merge pull request #6412 from dearblue/OP_RETURN_BLK

Distinguish the call frame of the generator with `OP_RETURN_BLK`
This commit is contained in:
Yukihiro "Matz" Matsumoto
2024-11-10 23:10:27 +09:00
committed by GitHub
2 changed files with 91 additions and 3 deletions
+5 -3
View File
@@ -233,11 +233,12 @@ uvenv(mrb_state *mrb, mrb_int up)
}
static inline const struct RProc*
top_proc(mrb_state *mrb, const struct RProc *proc)
top_proc(mrb_state *mrb, const struct RProc *proc, const struct REnv **envp)
{
while (proc->upper) {
if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc))
return proc;
*envp = proc->e.env;
proc = proc->upper;
}
return proc;
@@ -2294,11 +2295,12 @@ RETRY_TRY_BLOCK:
goto NORMAL_RETURN;
}
const struct RProc *dst = top_proc(mrb, ci->proc);
const struct REnv *env = ci->u.env;
const struct RProc *dst = top_proc(mrb, ci->proc, &env);
if (!MRB_PROC_ENV_P(dst) || dst->e.env->cxt == mrb->c) {
/* check jump destination */
for (ptrdiff_t i = ci - mrb->c->cibase; i >= 0; i--, ci--) {
if (ci->proc == dst) {
if (ci->u.env == env) {
goto L_UNWINDING;
}
}
+86
View File
@@ -532,3 +532,89 @@ assert('BS Block 39') do
}
end
end
assert('BS Block 40 (https://github.com/mruby/mruby/issues/6411)') do
assert_equal "GOOD" do
Object.new.instance_eval do
def test(&b)
if b
b.call
else
test { return "GOOD" }
end
"BAD"
end
test
end
end
assert_equal "GOOD" do
Object.new.instance_eval do
# since Kernel#proc is defined in proc-ext
def make_proc(&b)
b
end
def chocolate(&b)
biscuit(&b)
end
def biscuit(&b)
if b
b.call
else
b = make_proc { return "GOOD" }
chocolate(&b)
end
"BAD"
end
biscuit
end
end
assert_equal [0, 1, 2, 3] do
Object.new.instance_eval do
def test(a = [], &b)
if b
b.call
else
if a.empty?
a << 0
test(a)
else
a << 1
test(a) { return 1 }
end
a << 2
end
a << 3
end
test
end
end
assert_equal [0, 1, 3, 2, 3, 2, 3] do
Object.new.instance_eval do
def test(a = [], &b)
if b
b.call
else
if a.empty?
a << 0
test(a)
else
a << 1
test(a, &-> { return 1 })
end
a << 2
end
a << 3
end
test
end
end
end