diff --git a/ChangeLog b/ChangeLog index 1a49e9b2ed..ad0759df67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Jun 27 21:31:13 2012 Nobuyoshi Nakada + + * class.c (rb_prepend_module): ancestors of prepending module also + should be included. [ruby-core:45914][Bug #6654] + Wed Jun 27 21:01:32 2012 Nobuyoshi Nakada * class.c (class_instance_method_list): m_tbl in prepended diff --git a/class.c b/class.c index 099f016d97..537401582a 100644 --- a/class.c +++ b/class.c @@ -650,10 +650,11 @@ include_class_new(VALUE module, VALUE super) return (VALUE)klass; } +static int include_modules_at(VALUE klass, VALUE c, VALUE module); + void rb_include_module(VALUE klass, VALUE module) { - VALUE p, c; int changed = 0; rb_frozen_class_p(klass); @@ -666,7 +667,17 @@ rb_include_module(VALUE klass, VALUE module) } OBJ_INFECT(klass, module); - c = klass; + + changed = include_modules_at(klass, klass, module); + if (changed) rb_clear_cache(); +} + +static int +include_modules_at(VALUE klass, VALUE c, VALUE module) +{ + VALUE p; + int changed = 0; + while (module) { int superclass_seen = FALSE; @@ -696,13 +707,15 @@ rb_include_module(VALUE klass, VALUE module) skip: module = RCLASS_SUPER(module); } - if (changed) rb_clear_cache(); + + return changed; } void rb_prepend_module(VALUE klass, VALUE module) { VALUE p, c, origin; + int changed = 0; rb_frozen_class_p(klass); if (!OBJ_UNTRUSTED(klass)) { @@ -714,7 +727,7 @@ rb_prepend_module(VALUE klass, VALUE module) OBJ_INFECT(klass, module); c = RCLASS_SUPER(klass); if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module)) - rb_raise(rb_eArgError, "cyclic include detected"); + rb_raise(rb_eArgError, "cyclic prepend detected"); for (p = c; p; p = RCLASS_SUPER(p)) { if (BUILTIN_TYPE(p) == T_ICLASS) { if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) { @@ -733,9 +746,12 @@ rb_prepend_module(VALUE klass, VALUE module) c = origin; } RCLASS_SUPER(klass) = include_class_new(module, c); - if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) { - rb_clear_cache_by_class(klass); + if (RCLASS_SUPER(module)) { + changed = include_modules_at(klass, RCLASS_SUPER(klass), RCLASS_SUPER(module)); } + if (!changed) + changed = RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries; + if (changed) rb_clear_cache(); } /* diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 5826ed0269..7f66911e43 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -1271,6 +1271,15 @@ class TestModule < Test::Unit::TestCase assert_equal(expected, obj.m1) end + def test_prepend_inheritance + bug6654 = '[ruby-core:45914]' + a = Module.new + b = Module.new {include a} + c = Class.new {prepend b} + assert_operator(c, :<, b, bug6654) + assert_operator(c, :<, a, bug6654) + end + def test_prepend_instance_methods bug6655 = '[ruby-core:45915]' assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655)