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/