ruby-changes:48013
From: nobu <ko1@a...>
Date: Fri, 6 Oct 2017 14:55:15 +0900 (JST)
Subject: [ruby-changes:48013] nobu:r60127 (trunk): proc.c: super_method of included method
nobu 2017-10-06 14:55:11 +0900 (Fri, 06 Oct 2017) New Revision: 60127 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60127 Log: proc.c: super_method of included method * proc.c (method_super_method): search the next super method along the included ancestor chain. [ruby-core:83114] [Bug #13973] * vm_method.c (rb_callable_method_entry_without_refinements): return the defined class. Modified files: trunk/method.h trunk/proc.c trunk/test/ruby/test_method.rb trunk/vm_args.c trunk/vm_insnhelper.c trunk/vm_method.c Index: test/ruby/test_method.rb =================================================================== --- test/ruby/test_method.rb (revision 60126) +++ test/ruby/test_method.rb (revision 60127) @@ -876,6 +876,16 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L876 m = m.super_method assert_equal(c1, m.owner, Feature9781) assert_same(o, m.receiver, Feature9781) + + c1 = Class.new {def foo; end} + c2 = Class.new(c1) {include m1; include m2} + m = c2.instance_method(:foo) + assert_equal(m2, m.owner) + m = m.super_method + assert_equal(m1, m.owner) + m = m.super_method + assert_equal(c1, m.owner) + assert_nil(m.super_method) end def test_super_method_removed Index: vm_method.c =================================================================== --- vm_method.c (revision 60126) +++ vm_method.c (revision 60127) @@ -863,31 +863,31 @@ method_entry_resolve_refinement(VALUE kl https://github.com/ruby/ruby/blob/trunk/vm_method.c#L863 } const rb_method_entry_t * -rb_method_entry_with_refinements(VALUE klass, ID id) +rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr) { - return method_entry_resolve_refinement(klass, id, TRUE, NULL); + return method_entry_resolve_refinement(klass, id, TRUE, defined_class_ptr); } const rb_callable_method_entry_t * -rb_callable_method_entry_with_refinements(VALUE klass, ID id) +rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr) { - VALUE defined_class; - const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, TRUE, &defined_class); - return prepare_callable_method_entry(defined_class, id, me); + VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class; + const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, TRUE, dcp); + return prepare_callable_method_entry(*dcp, id, me); } const rb_method_entry_t * -rb_method_entry_without_refinements(VALUE klass, ID id) +rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr) { - return method_entry_resolve_refinement(klass, id, FALSE, NULL); + return method_entry_resolve_refinement(klass, id, FALSE, defined_class_ptr); } const rb_callable_method_entry_t * -rb_callable_method_entry_without_refinements(VALUE klass, ID id) +rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr) { - VALUE defined_class; - const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, FALSE, &defined_class); - return prepare_callable_method_entry(defined_class, id, me); + VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class; + const rb_method_entry_t *me = method_entry_resolve_refinement(klass, id, FALSE, dcp); + return prepare_callable_method_entry(*dcp, id, me); } static const rb_method_entry_t * @@ -1067,7 +1067,7 @@ rb_export_method(VALUE klass, ID name, r https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1067 int rb_method_boundp(VALUE klass, ID id, int ex) { - const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id); + const rb_method_entry_t *me = rb_method_entry_without_refinements(klass, id, NULL); if (me != 0) { if ((ex & ~BOUND_RESPONDS) && @@ -1307,7 +1307,7 @@ check_definition(VALUE mod, VALUE mid, r https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1307 const rb_method_entry_t *me; ID id = rb_check_id(&mid); if (!id) return Qfalse; - me = rb_method_entry_without_refinements(mod, id); + me = rb_method_entry_without_refinements(mod, id, NULL); if (me) { if (METHOD_ENTRY_VISI(me) == visi) return Qtrue; } Index: method.h =================================================================== --- method.h (revision 60126) +++ method.h (revision 60127) @@ -187,13 +187,13 @@ rb_method_entry_t *rb_method_entry_creat https://github.com/ruby/ruby/blob/trunk/method.h#L187 const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id); const rb_method_entry_t *rb_method_entry(VALUE klass, ID id); -const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id); -const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id); +const rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class); +const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class); const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me); const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id); -const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id); -const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id); +const rb_callable_method_entry_t *rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class); +const rb_callable_method_entry_t *rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class); const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me); int rb_method_entry_arity(const rb_method_entry_t *me); Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 60126) +++ vm_insnhelper.c (revision 60127) @@ -1470,7 +1470,8 @@ check_match(VALUE pattern, VALUE target, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1470 } /* fall through */ case VM_CHECKMATCH_TYPE_CASE: { - const rb_callable_method_entry_t *me = rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq); + const rb_callable_method_entry_t *me = + rb_callable_method_entry_with_refinements(CLASS_OF(pattern), idEqq, NULL); if (me) { return vm_call0(GET_THREAD(), pattern, idEqq, 1, &target, me); } @@ -2042,7 +2043,7 @@ vm_call_opt_send(rb_thread_t *th, rb_con https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2043 DEC_SP(1); } - cc->me = rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), ci->mid); + cc->me = rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), ci->mid, NULL); ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND; return vm_call_method(th, reg_cfp, calling, ci, cc); } @@ -2085,7 +2086,7 @@ vm_call_method_missing(rb_thread_t *th, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2086 cc_entry = *orig_cc; cc_entry.me = rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), - idMethodMissing); + idMethodMissing, NULL); cc = &cc_entry; calling->argc = argc; Index: vm_args.c =================================================================== --- vm_args.c (revision 60126) +++ vm_args.c (revision 60127) @@ -825,7 +825,7 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ https://github.com/ruby/ruby/blob/trunk/vm_args.c#L825 } obj = *argv++; mid = SYM2ID(callback_arg); - me = rb_callable_method_entry_with_refinements(CLASS_OF(obj), mid); + me = rb_callable_method_entry_with_refinements(CLASS_OF(obj), mid, NULL); th = GET_THREAD(); if (!NIL_P(blockarg)) { vm_passed_block_handler_set(th, blockarg); Index: proc.c =================================================================== --- proc.c (revision 60126) +++ proc.c (revision 60127) @@ -29,6 +29,7 @@ const rb_cref_t *rb_vm_cref_in_context(V https://github.com/ruby/ruby/blob/trunk/proc.c#L29 struct METHOD { const VALUE recv; const VALUE klass; + const VALUE iclass; const rb_method_entry_t * const me; /* for bound methods, `me' should be rb_callable_method_entry_t * */ }; @@ -1313,6 +1314,7 @@ bm_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/proc.c#L1314 struct METHOD *data = ptr; rb_gc_mark(data->recv); rb_gc_mark(data->klass); + rb_gc_mark(data->iclass); rb_gc_mark((VALUE)data->me); } @@ -1380,7 +1382,7 @@ mnew_missing(VALUE klass, VALUE obj, ID https://github.com/ruby/ruby/blob/trunk/proc.c#L1382 } static VALUE -mnew_internal(const rb_method_entry_t *me, VALUE klass, +mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, VALUE obj, ID id, VALUE mclass, int scope, int error) { struct METHOD *data; @@ -1406,24 +1408,21 @@ mnew_internal(const rb_method_entry_t *m https://github.com/ruby/ruby/blob/trunk/proc.c#L1408 if (me->defined_class) { VALUE klass = RCLASS_SUPER(RCLASS_ORIGIN(me->defined_class)); id = me->def->original_id; - me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id); + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id, &iclass); } else { VALUE klass = RCLASS_SUPER(me->owner); id = me->def->original_id; - me = rb_method_entry_without_refinements(klass, id); + me = rb_method_entry_without_refinements(klass, id, &iclass); } goto again; } - while (klass != me->owner && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { - klass = RCLASS_SUPER(klass); - } - method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); RB_OBJ_WRITE(method, &data->recv, obj); RB_OBJ_WRITE(method, &data->klass, klass); + RB_OBJ_WRITE(method, &data->iclass, iclass); RB_OBJ_WRITE(method, &data->me, me); OBJ_INFECT(method, klass); @@ -1431,24 +1430,25 @@ mnew_internal(const rb_method_entry_t *m https://github.com/ruby/ruby/blob/trunk/proc.c#L1430 } static VALUE -mnew_from_me(const rb_method_entry_t *me, VALUE klass, +mnew_from_me(const rb_method_entry_t *me, VALUE klass, VALUE iclass, VALUE obj, ID id, VALUE mclass, int scope) { - return mnew_internal(me, klass, obj, id, mclass, scope, TRUE); + return mnew_internal(me, klass, iclass, obj, id, mclass, scope, TRUE); } static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { const rb_method_entry_t *me; + VALUE iclass = Qnil; if (obj == Qundef) { /* UnboundMethod */ - me = rb_method_entry_without_refinements(klass, id); + me = rb_method_entry_without_refinements(klass, id, &iclass); } else { - me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id); + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(klass, id, &iclass); } - return mnew_from_me(me, klass, obj, id, mclass, scope); + return mnew_from_me(me, klass, iclass, obj, id, mclass, scope); } static inline VALUE @@ -1778,7 +1778,7 @@ rb_obj_singleton_method(VALUE obj, VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L1778 vid = ID2SYM(id); goto undef; } - return mnew_from_me(me, klass, obj, id, rb_cMethod, FALSE); + return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE); } /* @@ -2694,15 +2694,18 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L2694 method_super_method(VALUE method) { const struct METHOD *data; - VALUE super_class; + VALUE super_class, iclass; + ID mid; const rb_method_entry_t *me; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); - super_class = RCLASS_SUPER(RCLASS_ORIGIN(method_entry_defined_class(data->me))); + iclass = data->iclass; + super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); + mid = data->me->called_id; if (!super_class) return Qnil; - me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, data->me->called_id); + me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, mid, &iclass); if (!me) return Qnil; - return mnew_internal(me, super_class, data->recv, data->me->called_id, rb_obj_class(method), FALSE, FALSE); + return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE); } /* -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/