Skip to content

Commit 0108926

Browse files
koutsahara
authored andcommitted
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. Conflicts: src/vm.c
1 parent cf78233 commit 0108926

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

src/vm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int
14151415
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
14161416
goto L_RAISE;
14171417
}
1418+
mrb->c->stack = mrb->c->ci->stackent;
14181419
mrb->c->ci = ci;
14191420
break;
14201421
}
@@ -1448,6 +1449,7 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int
14481449
mrb->c = c->prev;
14491450
c->prev = NULL;
14501451
}
1452+
mrb->c->stack = mrb->c->ci->stackent;
14511453
ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
14521454
break;
14531455
default:

test/t/ensure.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
##
2+
# ensure Test
3+
4+
assert('ensure - context - yield') do
5+
class EnsureYieldBreak
6+
attr_reader :ensure_context
7+
def try
8+
yield
9+
ensure
10+
@ensure_context = self
11+
end
12+
end
13+
14+
yielder = EnsureYieldBreak.new
15+
yielder.try do
16+
end
17+
assert_equal yielder, yielder.ensure_context
18+
end
19+
20+
assert('ensure - context - yield and break') do
21+
class EnsureYieldBreak
22+
attr_reader :ensure_context
23+
def try
24+
yield
25+
ensure
26+
@ensure_context = self
27+
end
28+
end
29+
30+
yielder = EnsureYieldBreak.new
31+
yielder.try do
32+
break
33+
end
34+
assert_equal yielder, yielder.ensure_context
35+
end
36+
37+
assert('ensure - context - yield and return') do
38+
class EnsureYieldBreak
39+
attr_reader :ensure_context
40+
def try
41+
yield
42+
ensure
43+
@ensure_context = self
44+
end
45+
end
46+
47+
yielder = EnsureYieldBreak.new
48+
lambda do
49+
yielder.try do
50+
return
51+
end
52+
end.call
53+
assert_equal yielder, yielder.ensure_context
54+
end

0 commit comments

Comments
 (0)