diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-08-17 00:17:15 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-08-17 12:30:38 +0900 |
commit | 11a9f7ab9431b0f361e43b4ac2bd6ee44827d88b (patch) | |
tree | f2ebdeb3b5430a65b4d0ee1e76afef7e729e3109 | |
parent | 042be439d92ea0910fe3bd0d5e9a1d4135257d2d (diff) | |
download | ruby-11a9f7ab9431b0f361e43b4ac2bd6ee44827d88b.tar.gz |
Search refinement module along nested usings
[Bug #16107]
-rw-r--r-- | test/ruby/test_refinement.rb | 28 | ||||
-rw-r--r-- | vm_insnhelper.c | 56 |
2 files changed, 55 insertions, 29 deletions
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index afb4784d00..87d60e41a4 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -2295,6 +2295,34 @@ class TestRefinement < Test::Unit::TestCase d end + class RefineInUsing + module M1 + refine RefineInUsing do + def foo + :ok + end + end + end + + module M2 + using M1 + refine RefineInUsing do + def call_foo + RefineInUsing.new.foo + end + end + end + + using M2 + def self.test + new.call_foo + end + end + + def test_refine_in_using + assert_equal(:ok, RefineInUsing.test) + end + private def eval_using(mod, s) diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 2d765e1e95..d2982afdfa 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2604,39 +2604,37 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st case VM_METHOD_TYPE_REFINED: { const rb_cref_t *cref = vm_get_cref(cfp->ep); - VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil; - VALUE refinement; - const rb_callable_method_entry_t *ref_me; - refinement = find_refinement(refinements, cc->me->owner); + for (; cref; cref = CREF_NEXT(cref)) { + const rb_callable_method_entry_t *ref_me; + VALUE refinements = CREF_REFINEMENTS(cref); + VALUE refinement = find_refinement(refinements, cc->me->owner); + if (NIL_P(refinement)) continue; - if (NIL_P(refinement)) { - goto no_refinement_dispatch; - } - ref_me = rb_callable_method_entry(refinement, ci->mid); - - if (ref_me) { - if (cc->call == vm_call_super_method) { - const rb_control_frame_t *top_cfp = current_method_entry(ec, cfp); - const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp); - if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) { - goto no_refinement_dispatch; - } - } - if (cc->me->def->type != VM_METHOD_TYPE_REFINED || - cc->me->def != ref_me->def) { - cc->me = ref_me; + ref_me = rb_callable_method_entry(refinement, ci->mid); + + if (ref_me) { + if (cc->call == vm_call_super_method) { + const rb_control_frame_t *top_cfp = current_method_entry(ec, cfp); + const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp); + if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) { + continue; + } + } + if (cc->me->def->type != VM_METHOD_TYPE_REFINED || + cc->me->def != ref_me->def) { + cc->me = ref_me; + } + if (ref_me->def->type != VM_METHOD_TYPE_REFINED) { + return vm_call_method(ec, cfp, calling, ci, cc); + } } - if (ref_me->def->type != VM_METHOD_TYPE_REFINED) { - return vm_call_method(ec, cfp, calling, ci, cc); - } - } - else { - cc->me = NULL; - return vm_call_method_nome(ec, cfp, calling, ci, cc); - } + else { + cc->me = NULL; + return vm_call_method_nome(ec, cfp, calling, ci, cc); + } + } - no_refinement_dispatch: if (cc->me->def->body.refined.orig_me) { cc->me = refined_method_callable_without_refinement(cc->me); } |