summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proc.c13
-rw-r--r--test/ruby/test_method.rb80
-rw-r--r--vm_insnhelper.c6
3 files changed, 94 insertions, 5 deletions
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);