From 12bd519a9b91fbb1b7f515b5c52b2c1e9084d85f Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 6 Oct 2017 05:55:11 +0000 Subject: 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60127 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- method.h | 8 ++++---- proc.c | 37 ++++++++++++++++++++----------------- test/ruby/test_method.rb | 10 ++++++++++ vm_args.c | 2 +- vm_insnhelper.c | 7 ++++--- vm_method.c | 28 ++++++++++++++-------------- 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/method.h b/method.h index 57a8602566..acdf67f762 100644 --- a/method.h +++ b/method.h @@ -187,13 +187,13 @@ rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_v 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); diff --git a/proc.c b/proc.c index d8a4fabdb5..021442ad93 100644 --- a/proc.c +++ b/proc.c @@ -29,6 +29,7 @@ const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); 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) 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 id, VALUE mclass) } 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 *me, VALUE klass, 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 *me, VALUE klass, } 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 vid) 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 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); } /* diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 6e201911f9..ce67aada2b 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -876,6 +876,16 @@ class TestMethod < Test::Unit::TestCase 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 diff --git a/vm_args.c b/vm_args.c index 19eae944d0..2a09eb262a 100644 --- a/vm_args.c +++ b/vm_args.c @@ -825,7 +825,7 @@ refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) } 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); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 1678100eab..652b3d8133 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1470,7 +1470,8 @@ check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) } /* 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_control_frame_t *reg_cfp, struct rb_calling 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, rb_control_frame_t *reg_cfp, struct rb_c 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; diff --git a/vm_method.c b/vm_method.c index f429048726..2320b54aed 100644 --- a/vm_method.c +++ b/vm_method.c @@ -863,31 +863,31 @@ method_entry_resolve_refinement(VALUE klass, ID id, int with_refinement, VALUE * } 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, rb_method_visibility_t visi) 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, rb_method_visibility_t visi) 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; } -- cgit v1.2.3