diff options
-rw-r--r-- | proc.c | 13 | ||||
-rw-r--r-- | test/ruby/test_method.rb | 80 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rw-r--r-- | vm_insnhelper.c | 6 |
4 files changed, 95 insertions, 6 deletions
@@ -2760,6 +2760,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 @@ -2779,8 +2781,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_without_refinements(super_class, mid, &iclass); if (!me) return Qnil; diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 2d615ca53f..1df09c21b7 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -958,6 +958,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 @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.6.7" #define RUBY_RELEASE_DATE "2021-04-05" -#define RUBY_PATCHLEVEL 192 +#define RUBY_PATCHLEVEL 193 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 4 diff --git a/vm_insnhelper.c b/vm_insnhelper.c index b3a89fca06..0a018bdd54 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2161,8 +2161,8 @@ current_method_entry(const rb_execution_context_t *ec, rb_control_frame_t *cfp) return cfp; } -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; @@ -2187,7 +2187,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); |