From b53ccb9c69abd24e3bdad66cbe4c7e7480eaef16 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 11 Dec 2020 11:54:50 +0900 Subject: [PATCH] show deprecation warning correctly for lambda(&b) lambda(&b) where b is given block of method (like: def foo(&b)) should warn correctly. [Feature #17361] Also labmda(&labmda_block) or lambda(&:to_s) (Symbol#to_proc) should not warn (but I'm not sure who cares about it). --- proc.c | 14 +++++++++++--- test/ruby/test_proc.rb | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/proc.c b/proc.c index ca70eb1a0a..7e1985ceb1 100644 --- a/proc.c +++ b/proc.c @@ -858,15 +858,23 @@ rb_block_lambda(void) static VALUE f_lambda(VALUE _) { - VALUE block_handler = rb_vm_frame_block_handler(GET_EC()->cfp); + rb_control_frame_t *cfp = GET_EC()->cfp; + VALUE block_handler = rb_vm_frame_block_handler(cfp); if (block_handler != VM_BLOCK_HANDLER_NONE) { switch (vm_block_handler_type(block_handler)) { - case block_handler_type_proc: + case block_handler_type_iseq: + if (RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)->ep == VM_BH_TO_ISEQ_BLOCK(block_handler)->ep) { + break; + } case block_handler_type_symbol: + break; + case block_handler_type_proc: + if (rb_proc_lambda_p(VM_BH_TO_PROC(block_handler))) { + break; + } case block_handler_type_ifunc: rb_warn_deprecated("lambda without a literal block", "the proc without lambda"); - default: break; } } diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index c1f17a003a..ca690dce0d 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -291,6 +291,45 @@ class TestProc < Test::Unit::TestCase assert_equal(true, Proc.new(&l).lambda?) end + def self.helper_test_warn_lamda_with_passed_block &b + lambda(&b) + end + + def self.def_lambda_warning name, warn + define_method(name, proc do + prev = Warning[:deprecated] + assert_warn warn do + Warning[:deprecated] = true + yield + end + ensure + Warning[:deprecated] = prev + end) + end + + def_lambda_warning 'test_lambda_warning_normal', '' do + lambda{} + end + + def_lambda_warning 'test_lambda_warning_pass_lambda', '' do + b = lambda{} + lambda(&b) + end + + def_lambda_warning 'test_lambda_warning_pass_proc', /deprecated/ do + b = proc{} + lambda(&b) + end + + def_lambda_warning 'test_lambda_warning_pass_proc', /deprecated/ do + helper_test_warn_lamda_with_passed_block{} + end + + def_lambda_warning 'test_lambda_warning_pass_proc', '' do + # Symbol#to_proc returns lambda + helper_test_warn_lamda_with_passed_block(&:to_s) + end + def test_curry_ski_fib s = proc {|f, g, x| f[x][g[x]] }.curry k = proc {|x, y| x }.curry