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

ruby-changes:59059

From: Jeremy <ko1@a...>
Date: Wed, 4 Dec 2019 08:35:55 +0900 (JST)
Subject: [ruby-changes:59059] a91637c516 (master): Make {Method, UnboundMethod}#super_method handle clone/bind/unbind

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

From a91637c516779d9ecee5f323e211f0ed71eb06ad Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Wed, 2 Oct 2019 15:20:10 -0700
Subject: Make {Method,UnboundMethod}#super_method handle clone/bind/unbind

This wasn't working previously because the iclass entry wasn't
being copied, and without an iclass entry, super_method returns
nil.

Fixes [Bug #15629]

diff --git a/proc.c b/proc.c
index 1144940..4d9998b 100644
--- a/proc.c
+++ b/proc.c
@@ -1686,6 +1686,7 @@ method_unbind(VALUE obj) https://github.com/ruby/ruby/blob/trunk/proc.c#L1686
 				   &method_data_type, data);
     RB_OBJ_WRITE(method, &data->recv, Qundef);
     RB_OBJ_WRITE(method, &data->klass, orig->klass);
+    RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
     RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
 
     return method;
@@ -2198,6 +2199,7 @@ method_clone(VALUE self) https://github.com/ruby/ruby/blob/trunk/proc.c#L2199
     CLONESETUP(clone, self);
     RB_OBJ_WRITE(clone, &data->recv, orig->recv);
     RB_OBJ_WRITE(clone, &data->klass, orig->klass);
+    RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
     RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
     return clone;
 }
@@ -2345,13 +2347,14 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe https://github.com/ruby/ruby/blob/trunk/proc.c#L2347
  */
 
 static void
-convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, const rb_method_entry_t **me_out)
+convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, VALUE *iclass_out, const rb_method_entry_t **me_out)
 {
     struct METHOD *data;
 
     TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
 
     VALUE methclass = data->me->owner;
+    VALUE iclass = data->me->defined_class;
     VALUE klass = CLASS_OF(recv);
 
     if (!RB_TYPE_P(methclass, T_MODULE) &&
@@ -2372,6 +2375,7 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_ https://github.com/ruby/ruby/blob/trunk/proc.c#L2375
 	VALUE ic = rb_class_search_ancestor(klass, me->owner);
 	if (ic) {
 	    klass = ic;
+            iclass = ic;
 	}
 	else {
 	    klass = rb_include_class_new(methclass, klass);
@@ -2381,6 +2385,7 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_ https://github.com/ruby/ruby/blob/trunk/proc.c#L2385
 
     *methclass_out = methclass;
     *klass_out = klass;
+    *iclass_out = iclass;
     *me_out = me;
 }
 
@@ -2422,14 +2427,15 @@ convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_ https://github.com/ruby/ruby/blob/trunk/proc.c#L2427
 static VALUE
 umethod_bind(VALUE method, VALUE recv)
 {
-    VALUE methclass, klass;
+    VALUE methclass, klass, iclass;
     const rb_method_entry_t *me;
-    convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
+    convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
 
     struct METHOD *bound;
     method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
     RB_OBJ_WRITE(method, &bound->recv, recv);
     RB_OBJ_WRITE(method, &bound->klass, klass);
+    RB_OBJ_WRITE(method, &bound->iclass, iclass);
     RB_OBJ_WRITE(method, &bound->me, me);
 
     return method;
@@ -2451,9 +2457,9 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2457
     argc--;
     argv++;
 
-    VALUE methclass, klass;
+    VALUE methclass, klass, iclass;
     const rb_method_entry_t *me;
-    convert_umethod_to_method_components(method, recv, &methclass, &klass, &me);
+    convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
     struct METHOD bound = { recv, klass, 0, me };
 
     VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index edd1da3..bb506f1 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -991,6 +991,36 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L991
     assert_nil(m.super_method)
   end
 
+  def test_super_method_bind_unbind_clone
+    bug15629_m1 = Module.new do
+      def foo; end
+    end
+
+    bug15629_m2 = Module.new do
+      def foo; end
+    end
+
+    bug15629_c = Class.new do
+      include bug15629_m1
+      include bug15629_m2
+    end
+
+    o  = bug15629_c.new
+    m = o.method(:foo)
+    sm = m.super_method
+    im = bug15629_c.instance_method(:foo)
+    sim = im.super_method
+
+    assert_equal(sm, m.clone.super_method)
+    assert_equal(sim, m.unbind.super_method)
+    assert_equal(sim, m.unbind.clone.super_method)
+    assert_equal(sim, im.clone.super_method)
+    assert_equal(sm, m.unbind.bind(o).super_method)
+    assert_equal(sm, m.unbind.clone.bind(o).super_method)
+    assert_equal(sm, im.bind(o).super_method)
+    assert_equal(sm, im.clone.bind(o).super_method)
+  end
+
   def test_super_method_removed
     c1 = Class.new {private def foo; end}
     c2 = Class.new(c1) {public :foo}
-- 
cgit v0.10.2


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

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