From 7ef16d224a80a6e1e8c01b5b45ac7e2315a04e4c Mon Sep 17 00:00:00 2001 From: shugo Date: Mon, 10 Dec 2012 16:05:45 +0000 Subject: * fix the behavior when a module is included into a refinement. This change is a little tricky, so it might be better to prohibit module inclusion to refinements. * include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag to represent that a module (iclass) is included into a refinement. * class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT if klass is a refinement. * eval.c (rb_mod_refine): set the superclass of a refinement to the refined class for super. * eval.c (rb_using_refinement): skip the above superclass (the refined class) when creating iclasses for refinements. Otherwise, `using Refinement1; using Refinement2' creates iclasses: -> -> -> RefinedClass, where is an iclass for Module, so RefinedClass is searched before Refinement1. The correct iclasses should be -> -> RefinedClass. * vm_insnhelper.c (vm_search_normal_superclass): if klass is an iclass for a refinement, use the refinement's superclass instead of the iclass's superclass. Otherwise, multiple refinements are searched by super. For example, if a refinement Refinement2 includes a module M (i.e., Refinement2 -> -> RefinedClass, and if refinements iclasses are -> ' -> -> RefinedClass, then super in should use Refinement2's superclass instead of 's superclass '. * vm_insnhelper.c (vm_search_super_method): do not raise a NotImplementError if current_defind_class is a module included into a refinement. Because of the change of vm_search_normal_superclass(), the receiver might not be an instance of the module('s iclass). * test/ruby/test_refinement.rb: related test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- eval.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index 886b526af3..c32b974363 100644 --- a/eval.c +++ b/eval.c @@ -1079,7 +1079,7 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module) c = iclass = rb_include_class_new(module, superclass); RCLASS_REFINED_CLASS(c) = klass; module = RCLASS_SUPER(module); - while (module) { + while (module && module != klass) { FL_SET(module, RMODULE_IS_OVERLAID); c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c)); RCLASS_REFINED_CLASS(c) = klass; @@ -1193,6 +1193,7 @@ rb_mod_refine(VALUE module, VALUE klass) refinement = rb_hash_lookup(refinements, klass); if (NIL_P(refinement)) { refinement = rb_module_new(); + RCLASS_SUPER(refinement) = klass; FL_SET(refinement, RMODULE_IS_REFINEMENT); CONST_ID(id_refined_class, "__refined_class__"); rb_ivar_set(refinement, id_refined_class, klass); -- cgit v1.2.3