From: Kazuki Tsujimoto Date: 2011-05-14T23:26:34+09:00 Subject: [ruby-dev:43551] yieldされたlambdaからのreturn/breakの動きについて 辻本です。 lambdaとprocは、return/breakの動きと引数の数のチェックの動きに違いがありますが、 ブロックとして渡したlambdaをyieldで呼び出すとreturn/breakがproc相当になります (引数チェックはlambda相当のままです)。これは意図された挙動でしょうか。 # ruby -v : ruby 1.9.3dev (2011-05-14 trunk 31568) [x86_64-linux] def f g(&->{return 0}) # breakについても同様 1 end def g yield end p f #=> 0 なお、vm_invoke_blockで無条件にBLOCKフレームを積んでいるのが原因なので、 ブロックの種類に応じてLAMBDAフレームを積むようにすれば上記のコードで1が返るようになります。 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 + }) +} -- Kazuki Tsujimoto