diff --git a/class.c b/class.c index e03ba22576..f9e2322aeb 100644 --- a/class.c +++ b/class.c @@ -890,6 +890,8 @@ add_refined_method_entry_i(ID key, VALUE value, void *data) return ID_TABLE_CONTINUE; } +static void ensure_origin(VALUE klass); + static int include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) { @@ -897,6 +899,10 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) int method_changed = 0, constant_changed = 0; struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass)); + if (FL_TEST(module, RCLASS_REFINED_BY_ANY)) { + ensure_origin(module); + } + while (module) { int superclass_seen = FALSE; struct rb_id_table *tbl; @@ -978,15 +984,10 @@ move_refined_method(ID key, VALUE value, void *data) } } -void -rb_prepend_module(VALUE klass, VALUE module) +static void +ensure_origin(VALUE klass) { - VALUE origin; - int changed = 0; - - ensure_includable(klass, module); - - origin = RCLASS_ORIGIN(klass); + VALUE origin = RCLASS_ORIGIN(klass); if (origin == klass) { origin = class_alloc(T_ICLASS, klass); OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */ @@ -997,6 +998,16 @@ rb_prepend_module(VALUE klass, VALUE module) RCLASS_M_TBL_INIT(klass); rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass); } +} + +void +rb_prepend_module(VALUE klass, VALUE module) +{ + VALUE origin; + int changed = 0; + + ensure_includable(klass, module); + ensure_origin(klass); changed = include_modules_at(klass, klass, module, FALSE); if (changed < 0) rb_raise(rb_eArgError, "cyclic prepend detected"); diff --git a/eval.c b/eval.c index 77b0efa0fc..7bcb5447b7 100644 --- a/eval.c +++ b/eval.c @@ -1542,6 +1542,9 @@ rb_mod_refine(VALUE module, VALUE klass) } ensure_class_or_module(klass); + if (RB_TYPE_P(klass, T_MODULE)) { + FL_SET(klass, RCLASS_REFINED_BY_ANY); + } CONST_ID(id_refinements, "__refinements__"); refinements = rb_attr_get(module, id_refinements); if (NIL_P(refinements)) { diff --git a/internal.h b/internal.h index 50c129e7cd..ca635c9e36 100644 --- a/internal.h +++ b/internal.h @@ -1081,6 +1081,7 @@ int rb_singleton_class_internal_p(VALUE sklass); #define RCLASS_CLONED FL_USER6 #define RICLASS_IS_ORIGIN FL_USER5 +#define RCLASS_REFINED_BY_ANY FL_USER7 static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin) diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 618175f931..6fb04de5d6 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -2350,6 +2350,38 @@ class TestRefinement < Test::Unit::TestCase assert_equal("refine_method", Bug16242::X.new.hoge) end + module Bug13446 + module Enumerable + def sum(*args) + i = 0 + args.each { |arg| i += a } + i + end + end + + using Module.new { + refine Enumerable do + alias :orig_sum :sum + end + } + + module Enumerable + def sum(*args) + orig_sum(*args) + end + end + + class GenericEnumerable + include Enumerable + end + + Enumerable.prepend(Module.new) + end + + def test_prepend_refined_module + assert_equal(0, Bug13446::GenericEnumerable.new.sum) + end + private def eval_using(mod, s)