Project

General

Profile

Actions

Bug #14068

closed

Unused refinement breaks method search

Added by mame (Yusuke Endoh) about 7 years ago. Updated almost 7 years ago.

Status:
Closed
Target version:
ruby -v:
ruby 2.5.0dev (2017-10-30 trunk 60565) [x86_64-linux]
[ruby-core:83613]

Description

The following is an expected behavior.

module M1
  def foo
    p "M1#foo"
  end
end

module M2
end

include M1
include M2
foo() #=> "M1#foo"

But, defining UnusedRefinement that refines M2, breaks the behavior, even if it is entirely not used.

module M1
  def foo
    p "M1#foo"
  end
end

module M2
end

module UnusedRefinement # <=== INSERTED
  refine(M2) do
    def foo
      p "M2#foo"
    end
  end
end

include M1
include M2
foo() #=> test.rb:20:in `<main>': undefined method `foo' for main:Object (NoMethodError)
Actions #1

Updated by hsbt (Hiroshi SHIBATA) almost 7 years ago

  • Status changed from Open to Assigned

Updated by shugo (Shugo Maeda) almost 7 years ago

  • Assignee changed from shugo (Shugo Maeda) to ko1 (Koichi Sasada)

mame (Yusuke Endoh) wrote:

But, defining UnusedRefinement that refines M2, breaks the behavior, even if it is entirely not used.

When a method is refined, a VM_METHOD_TYPE_REFINED entry is defined at the target module even if
the refinement is not used.

When the method is called, and if the refinement is not used in the scope, vm_call_method_each_type()
falls back to the following code:

      no_refinement_dispatch:
	if (cc->me->def->body.refined.orig_me) {
	    cc->me = refined_method_callable_without_refinement(cc->me);
	}
	else {
	    VALUE klass = RCLASS_SUPER(cc->me->owner);
	    cc->me = klass ? rb_callable_method_entry(klass, ci->mid) : NULL;
	}
	return vm_call_method(ec, cfp, calling, ci, cc);
      }

However, cc-me->owner is not an iclass, but a module, so the method entry
is not found.

Is there any way to get an iclass here, ko1?
Otherwise, we may have to abandon refining modules....

Updated by shugo (Shugo Maeda) almost 7 years ago

The following patch seems to fix the problem:

diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 3c08a74..9a2f3cb 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2314,7 +2314,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
 	    cc->me = refined_method_callable_without_refinement(cc->me);
 	}
 	else {
-	    VALUE klass = RCLASS_SUPER(cc->me->owner);
+	    VALUE klass = RCLASS_SUPER(cc->me->defined_class);
 	    cc->me = klass ? rb_callable_method_entry(klass, ci->mid) : NULL;
 	}
 	return vm_call_method(ec, cfp, calling, ci, cc);
Actions #4

Updated by shugo (Shugo Maeda) almost 7 years ago

  • Status changed from Assigned to Closed

Applied in changeset trunk|r60931.


Unused module refinement shouldn't break method search.

Use rb_callable_method_entry_t::defined_class instead of
rb_callable_method_entry_t::owner, because the superclass of iclass
should be searched for modules. [ruby-core:83613] [Bug #14068]

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0