summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--class.c28
-rw-r--r--test/ruby/test_module.rb9
3 files changed, 36 insertions, 6 deletions
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 <nobu@ruby-lang.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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)