[前][次][番号順一覧][スレッド一覧]

ruby-changes:65777

From: usa <ko1@a...>
Date: Mon, 5 Apr 2021 09:12:37 +0900 (JST)
Subject: [ruby-changes:65777] 04601ea6c8 (ruby_2_6): merge revision(s) c60aaed1856b2b6f90de0992c34771830019e021: [Backport #17130]

https://git.ruby-lang.org/ruby.git/commit/?id=04601ea6c8

From 04601ea6c80a97b62a094b315fcd6f1a088bb722 Mon Sep 17 00:00:00 2001
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Mon, 5 Apr 2021 00:12:27 +0000
Subject: merge revision(s) c60aaed1856b2b6f90de0992c34771830019e021: [Backport
 #17130]

	Fix Method#super_method for aliased methods

	Previously, Method#super_method looked at the called_id to
	determine the method id to use, but that isn't correct for
	aliased methods, because the super target depends on the
	original method id, not the called_id.

	Additionally, aliases can reference methods defined in other
	classes and modules, and super lookup needs to start in the
	super of the defined class in such cases.

	This adds tests for Method#super_method for both types of
	aliases, one that uses VM_METHOD_TYPE_ALIAS and another that
	does not. Both check that the results for calling super
	methods return the expected values.

	To find the defined class for alias methods, add an rb_ prefix
	to find_defined_class_by_owner in vm_insnhelper.c and make it
	non-static, so that it can be called from method_super_method
	in proc.c.

	This bug was original discovered while researching [Bug #11189].

	Fixes [Bug #17130]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@67933 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
 proc.c                   | 13 ++++++--
 test/ruby/test_method.rb | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
 version.h                |  2 +-
 vm_insnhelper.c          |  6 ++--
 4 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/proc.c b/proc.c
index c18ea23..d3d75cb 100644
--- a/proc.c
+++ b/proc.c
@@ -2760,6 +2760,8 @@ method_to_proc(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2760
     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) https://github.com/ruby/ruby/blob/trunk/proc.c#L2781
     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 2d615ca..1df09c2 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -958,6 +958,86 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L958
       '[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/version.h b/version.h
index b359e8b..382b1c0 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/version.h#L1
 #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 b3a89fc..0a018bd 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) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2161
     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) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2187
     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);
 
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]