diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | proc.c | 12 | ||||
-rw-r--r-- | test/ruby/test_super.rb | 24 | ||||
-rw-r--r-- | vm_insnhelper.c | 1 |
4 files changed, 44 insertions, 2 deletions
@@ -1,3 +1,12 @@ +Fri Apr 11 15:05:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * proc.c (rb_method_call_with_block, umethod_bind): call with + IClass including the module for a module instance method. + [ruby-core:61936] [Bug #9721] + + * vm_insnhelper.c (vm_search_super_method): allow bound + UnboundMethod case. + Fri Apr 11 12:02:30 2014 NARUSE, Yui <naruse@ruby-lang.org> * addr2line.c (rb_dump_backtrace_with_lines): set base address @@ -1891,6 +1891,7 @@ rb_method_call_with_block(int argc, VALUE *argv, VALUE method, VALUE pass_procva if ((state = EXEC_TAG()) == 0) { rb_thread_t *th = GET_THREAD(); rb_block_t *block = 0; + VALUE defined_class; if (!NIL_P(pass_procval)) { rb_proc_t *pass_proc; @@ -1900,7 +1901,9 @@ rb_method_call_with_block(int argc, VALUE *argv, VALUE method, VALUE pass_procva th->passed_block = block; VAR_INITIALIZED(data); - result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, data->defined_class); + defined_class = data->defined_class; + if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass; + result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me, defined_class); } POP_TAG(); if (safe >= 0) @@ -2006,6 +2009,7 @@ umethod_bind(VALUE method, VALUE recv) { struct METHOD *data, *bound; VALUE methclass; + VALUE rclass; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); @@ -2027,8 +2031,12 @@ umethod_bind(VALUE method, VALUE recv) bound->me = ALLOC(rb_method_entry_t); *bound->me = *data->me; if (bound->me->def) bound->me->def->alias_count++; + rclass = CLASS_OF(recv); + if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) { + rclass = rb_include_class_new(methclass, rclass); + } bound->recv = recv; - bound->rclass = CLASS_OF(recv); + bound->rclass = rclass; data->ume = ALLOC(struct unlinked_method_entry_list_entry); return method; diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index fcf5773501..e7825560ac 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -452,4 +452,28 @@ class TestSuper < Test::Unit::TestCase m.call end end + + def test_super_in_module_unbound_method + bug9721 = '[ruby-core:61936] [Bug #9721]' + + a = Module.new do + def foo(result) + result << "A" + end + end + + b = Module.new do + def foo(result) + result << "B" + super + end + end + + m = b.instance_method(:foo).bind(Object.new.extend(a)) + result = [] + assert_nothing_raised(NoMethodError, bug9721) do + m.call(result) + end + assert_equal(%w[B A], result, bug9721) + end end diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 8627701b3e..dc752e7963 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2034,6 +2034,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf } if (BUILTIN_TYPE(current_defined_class) != T_MODULE && + BUILTIN_TYPE(current_defined_class) != T_ICLASS && /* bound UnboundMethod */ !FL_TEST(current_defined_class, RMODULE_INCLUDED_INTO_REFINEMENT) && !rb_obj_is_kind_of(ci->recv, current_defined_class)) { VALUE m = RB_TYPE_P(current_defined_class, T_ICLASS) ? |