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

ruby-changes:65945

From: Jeremy <ko1@a...>
Date: Sat, 24 Apr 2021 08:31:32 +0900 (JST)
Subject: [ruby-changes:65945] 4b36a597f4 (master): Fix setting method visibility for a refinement without an origin class

https://git.ruby-lang.org/ruby.git/commit/?id=4b36a597f4

From 4b36a597f48c857aa5eb9ed80fec0d02f6284646 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Mon, 5 Apr 2021 16:01:46 -0700
Subject: Fix setting method visibility for a refinement without an origin
 class

If a class has been refined but does not have an origin class,
there is a single method entry marked with VM_METHOD_TYPE_REFINED,
but it contains the original method entry.  If the original method
entry is present, we shouldn't skip the method when searching even
when skipping refined methods.

Fixes [Bug #17519]
---
 test/ruby/test_module.rb | 110 ++++++++++++++++++++++++++++++++++++++++++++++-
 vm_method.c              |   3 +-
 2 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index 3cd2f04..84e7469 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -2294,7 +2294,7 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L2294
     assert_equal(0, 1 / 2)
   end
 
-  def test_visibility_after_refine_and_visibility_change
+  def test_visibility_after_refine_and_visibility_change_with_origin_class
     m = Module.new
     c = Class.new do
       def x; :x end
@@ -2317,6 +2317,114 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L2317
     assert_equal(:x, o2.public_send(:x))
   end
 
+  def test_visibility_after_multiple_refine_and_visibility_change_with_origin_class
+    m = Module.new
+    c = Class.new do
+      def x; :x end
+    end
+    c.prepend(m)
+    Module.new do
+      refine c do
+        def x; :y end
+      end
+    end
+    Module.new do
+      refine c do
+        def x; :z end
+      end
+    end
+
+    o1 = c.new
+    o2 = c.new
+    assert_equal(:x, o1.public_send(:x))
+    assert_equal(:x, o2.public_send(:x))
+    o1.singleton_class.send(:private, :x)
+    o2.singleton_class.send(:public, :x)
+
+    assert_raise(NoMethodError) { o1.public_send(:x) }
+    assert_equal(:x, o2.public_send(:x))
+  end
+
+  def test_visibility_after_refine_and_visibility_change_without_origin_class
+    c = Class.new do
+      def x; :x end
+    end
+    Module.new do
+      refine c do
+        def x; :y end
+      end
+    end
+    o1 = c.new
+    o2 = c.new
+    o1.singleton_class.send(:private, :x)
+    o2.singleton_class.send(:public, :x)
+    assert_raise(NoMethodError) { o1.public_send(:x) }
+    assert_equal(:x, o2.public_send(:x))
+  end
+
+  def test_visibility_after_multiple_refine_and_visibility_change_without_origin_class
+    c = Class.new do
+      def x; :x end
+    end
+    Module.new do
+      refine c do
+        def x; :y end
+      end
+    end
+    Module.new do
+      refine c do
+        def x; :z end
+      end
+    end
+    o1 = c.new
+    o2 = c.new
+    o1.singleton_class.send(:private, :x)
+    o2.singleton_class.send(:public, :x)
+    assert_raise(NoMethodError) { o1.public_send(:x) }
+    assert_equal(:x, o2.public_send(:x))
+  end
+
+  def test_visibility_after_refine_and_visibility_change_with_superclass
+    c = Class.new do
+      def x; :x end
+    end
+    sc = Class.new(c)
+    Module.new do
+      refine sc do
+        def x; :y end
+      end
+    end
+    o1 = sc.new
+    o2 = sc.new
+    o1.singleton_class.send(:private, :x)
+    o2.singleton_class.send(:public, :x)
+    assert_raise(NoMethodError) { o1.public_send(:x) }
+    assert_equal(:x, o2.public_send(:x))
+  end
+
+  def test_visibility_after_multiple_refine_and_visibility_change_with_superclass
+    c = Class.new do
+      def x; :x end
+    end
+    sc = Class.new(c)
+    Module.new do
+      refine sc do
+        def x; :y end
+      end
+    end
+    Module.new do
+      refine sc do
+        def x; :z end
+      end
+    end
+    o1 = sc.new
+    o2 = sc.new
+    o1.singleton_class.send(:private, :x)
+    o2.singleton_class.send(:public, :x)
+    assert_raise(NoMethodError) { o1.public_send(:x) }
+    assert_equal(:x, o2.public_send(:x))
+  end
+
   def test_prepend_visibility
     bug8005 = '[ruby-core:53106] [Bug #8005]'
     c = Class.new do
diff --git a/vm_method.c b/vm_method.c
index 0f25c51..ffb290d 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -977,7 +977,8 @@ search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L977
     for (; klass; klass = RCLASS_SUPER(klass)) {
 	RB_DEBUG_COUNTER_INC(mc_search_super);
         if ((me = lookup_method_table(klass, id)) != 0) {
-            if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED) {
+            if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED ||
+                    me->def->body.refined.orig_me) {
                 break;
             }
         }
-- 
cgit v1.1


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

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