diff --git a/proc.c b/proc.c index eb3e4bb73e..3f92ceb365 100644 --- a/proc.c +++ b/proc.c @@ -3116,6 +3116,8 @@ method_to_proc(VALUE method) return procval; } +extern VALUE rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner); + /* * call-seq: * meth.super_method -> method @@ -3135,8 +3137,15 @@ method_super_method(VALUE method) TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); iclass = data->iclass; if (!iclass) return Qnil; - super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); - mid = data->me->called_id; + if (data->me->def->type == VM_METHOD_TYPE_ALIAS) { + super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class, + data->me->def->body.alias.original_me->owner)); + mid = data->me->def->body.alias.original_me->def->original_id; + } + else { + super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); + mid = data->me->def->original_id; + } if (!super_class) return Qnil; me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass); if (!me) return Qnil; diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 43c6c6d44b..85c5c45bd6 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -1080,6 +1080,86 @@ class TestMethod < Test::Unit::TestCase '[ruby-core:85231] [Bug #14421]' end + def test_super_method_alias + c0 = Class.new do + def m1 + [:C0_m1] + end + def m2 + [:C0_m2] + end + end + + c1 = Class.new(c0) do + def m1 + [:C1_m1] + super + end + alias m2 m1 + end + + c2 = Class.new(c1) do + def m2 + [:C2_m2] + super + end + end + o1 = c2.new + assert_equal([:C2_m2, :C1_m1, :C0_m1], o1.m2) + + m = o1.method(:m2) + assert_equal([:C2_m2, :C1_m1, :C0_m1], m.call) + + m = m.super_method + assert_equal([:C1_m1, :C0_m1], m.call) + + m = m.super_method + assert_equal([:C0_m1], m.call) + + assert_nil(m.super_method) + end + + def test_super_method_alias_to_prepended_module + m = Module.new do + def m1 + [:P_m1] + super + end + + def m2 + [:P_m2] + super + end + end + + c0 = Class.new do + def m1 + [:C0_m1] + end + end + + c1 = Class.new(c0) do + def m1 + [:C1_m1] + super + end + prepend m + alias m2 m1 + end + + o1 = c1.new + assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], o1.m2) + + m = o1.method(:m2) + assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], m.call) + + m = m.super_method + assert_equal([:P_m1, :C1_m1, :C0_m1], m.call) + + m = m.super_method + assert_equal([:C1_m1, :C0_m1], m.call) + + m = m.super_method + assert_equal([:C0_m1], m.call) + + assert_nil(m.super_method) + end + def rest_parameter(*rest) rest end diff --git a/vm_insnhelper.c b/vm_insnhelper.c index e6228fb466..f1c293a50a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2673,8 +2673,8 @@ vm_call_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_c return vm_call_bmethod_body(ec, calling, cd, argv); } -static VALUE -find_defined_class_by_owner(VALUE current_class, VALUE target_owner) +MJIT_FUNC_EXPORTED VALUE +rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner) { VALUE klass = current_class; @@ -2702,7 +2702,7 @@ aliased_callable_method_entry(const rb_callable_method_entry_t *me) const rb_callable_method_entry_t *cme; if (orig_me->defined_class == 0) { - VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner); + VALUE defined_class = rb_find_defined_class_by_owner(me->defined_class, orig_me->owner); VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE)); cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class);