Yieldされたlambdaからのreturn/breakの動きについて

$BDTK$G$9!#(B

lambda$B$H(Bproc$B$O!"(Breturn/break$B$NF0$-$H0z?t$N?t$N%A%’%C%/$NF0$-$K0c$$$,$"$j$^$9$,!"(B
$B%V%m%C%/$H$7$FEO$7$?(Blambda$B$r(Byield$B$G8F$S=P$9$H(Breturn/break$B$,(Bproc$BAjEv$K$J$j$^$9(B
($B0z?t%A%’%C%/$O(Blambda$BAjEv$N$^$^$G$9(B)$B!#$3$l$O0U?^$5$l$?5sF0$G$7$g$&$+!#(B

ruby -v : ruby 1.9.3dev (2011-05-14 trunk 31568) [x86_64-linux]

def f
g(&->{return 0}) # break$B$K$D$$$F$bF1MM(B
1
end

def g
yield
end

p f #=> 0

$B$J$*!"(Bvm_invoke_block$B$GL5>r7o$K(BBLOCK$B%U%l!<%$r@Q$s$G$$$k$N$,860x$J$N$G!"(B $B%V%m%C%/$N<oN$K1~$8$F(BLAMBDA$B%U%l!<%$r@Q$$h$&$K$9$l$P>e5-$N%3!<%I$G(B1$B$,JV$k$h$&$K$J$j$^$9!#(B

diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 3398b95…4f98b08 100644
— a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -930,15 +930,17 @@ vm_invoke_block(rb_thread_t *th,
rb_control_frame_t *reg_cfp, rb_num_t num, rb_n
if (BUILTIN_TYPE(iseq) != T_NODE) {
int opt_pc;
const int arg_size = iseq->arg_size;

  • int is_lambda = block_proc_is_lambda(block->proc);
    VALUE * const rsp = GET_SP() - argc;
    SET_SP(rsp);

    CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max);
    opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0,

  •         block_proc_is_lambda(block->proc));
    
  •         is_lambda);
    

    vm_push_frame(th, iseq,

  •      VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp,
    
  •      is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK,
    
  •      block->self, (VALUE) block->dfp,
         iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp,
         iseq->local_size - arg_size);
    

diff --git a/bootstraptest/test_proc.rb b/bootstraptest/test_proc.rb
index 28a2377…c3ed8e3 100644
— a/bootstraptest/test_proc.rb
+++ b/bootstraptest/test_proc.rb
@@ -429,3 +429,22 @@ assert_equal ‘ok’, %q{
raise “ok”
}

+assert_equal ‘ok’, %q{

  • def m
  • yield
  • :ok
  • end
  • m(&lambda{
  • return :ng
  • })
    +}

+assert_equal ‘ok’, %q{

  • def m
  • yield
  • :ok
  • end
  • m(&lambda{
  • break :ng
  • })
    +}

$B?.2,$G$9!#(B

lambda$B$H(Bproc$B$O!"(Breturn/break$B$NF0$-$H0z?t$N?t$N%A%’%C%/$NF0$-$K0c$$$,$"$j$^$9$,!"(B

$B%V%m%C%/$H$7$FEO$7$?(Blambda$B$r(Byield$B$G8F$S=P$9$H(Breturn/break$B$,(Bproc$BAjEv$K$J$j$^$9(B

($B0z?t%A%’%C%/$O(Blambda$BAjEv$N$^$^$G$9(B)$B!#$3$l$O0U?^$5$l$?5sF0$G$7$g$&$+!#(B

JIS X 3017 $B$K$O(B
$B!V(BKernel.lambda $B%a%=%C%I$O(B Proc.new $B$HF1$8$h$&$K(B Proc
$B%/%i%9$N%$%s%9%?%s%9$r@8@.$9$k!#(B
$B$7$+$7!"(Byield $B<0$G8F$S=P$5$l$?>l9g$r=|$-!"%V%m%C%/$N<B9T=hM}$O(B
proc $B$N$H$3$m$G@bL@$7$?(B
$BJ}K!$H$O0[$J$k!W(B
$B$H$$$&46$8$N$3$H(B (JIS X 3017 $B$,<j85$KL5$$$N$G@53N$G$O$J$$$G$9(B)
$B$,=q$+$l$F$$$?$O$:$J$N$G!"(B
$B>/$J$/$H$b(B Ruby 1.8 $B7O$G$O(B yield $B$G8F$S=P$7$?>l9g$K(B proc
$BAjEv$K$J$k$N$O4|BTDL$j(B
$B$J$s$8$c$J$$$+$H;W$$$^$9!#(B

$BDTK$G$9!#(B

Subject: [ruby-dev:43552] Re:
yield$B$5$l$?(Blambda$B$+$i$N(Breturn/break$B$NF0$-$K$D$$$F(B
From: “Y. NOBUOKA” [email protected]
Date: Sun, 15 May 2011 00:31:53 +0900

JIS X 3017 $B$K$O(B
(snip)
$B>/$J$/$H$b(B Ruby 1.8 $B7O$G$O(B yield $B$G8F$S=P$7$?>l9g$K(B proc
$BAjEv$K$J$k$N$O4|BTDL$j(B
$B$J$s$8$c$J$$$+$H;W$$$^$9!#(B

JIS X 3017$B$OFI$s$@$3$H$,L5$+$C$?$N$GJY6/$K$J$j$^$7$?!#(B
$B$"$j$,$H$&$4$6$$$^$9!#(B

$B?.2,$G$9!#(B

$B8F$S=P$7B&$+$i$9$k$H%a%=%C%IFbIt$G(B yield $B$r;H$C$F$$$k$N$+(B
$B$I$&$+$o$+$i$J$$$N$G;EMM$H$7$FHyL/$J5$$b$7$^$9$M!#(B
$B0J2<$N$h$&$J(B 2 $B$D$N%a%=%C%I(B c1 $B$H(B c2
$B$r9M$($?$H$-!“N>J}$H$b(B
$BF1$85sF0$G$”$k$Y$-$J$N$G$O$J$$$+$H;W$&$N$G$9$,!"<B:]$O(B
$B0[$J$k5sF0$r$7$F$7$^$$$^$9!#!#(B

$B5DO@$NM>CO$O$"$k$N$G$O$J$$$+$H;W$$$^$9!#(B

def c1( &block )
yield
:method
end
def c2( &block )
block.call()
:method
end

yield $B8F$S=P$7$5$l$k$H(B, proc $B$HF1$807$$(B

p c1( &->(){ return :return_lambda } ) rescue p $!
p c1( &->(){ break :break_lambda } ) rescue p $!

block.call() $B$G8F$S=P$5$l$k$H(B lambda $BK\Mh$NF0$-(B

p c2( &->(){ return :return_lambda } ) rescue p $!
p c2( &->(){ break :break_lambda } ) rescue p $!

$ ruby -v tmp.rb
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]
#<LocalJumpError: unexpected return>
#<LocalJumpError: break from proc-closure>
:method
:method

($B:G=i$N(B LocalJumpError $B$O(B top $B%l%Y%k$G(B return
$B$7$h$&$H$7$?$?$aH/@8(B)