ancestor modules

* class.c (rb_prepend_module): ancestors of prepending module also
  should be included.  [ruby-core:45914][Bug #6654]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2012-06-27 12:31:17 +00:00
parent 48c04ad0d8
commit cf3a8f09b8
3 changed files with 36 additions and 6 deletions

View File

@ -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> Wed Jun 27 21:01:32 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* class.c (class_instance_method_list): m_tbl in prepended * class.c (class_instance_method_list): m_tbl in prepended

28
class.c
View File

@ -650,10 +650,11 @@ include_class_new(VALUE module, VALUE super)
return (VALUE)klass; return (VALUE)klass;
} }
static int include_modules_at(VALUE klass, VALUE c, VALUE module);
void void
rb_include_module(VALUE klass, VALUE module) rb_include_module(VALUE klass, VALUE module)
{ {
VALUE p, c;
int changed = 0; int changed = 0;
rb_frozen_class_p(klass); rb_frozen_class_p(klass);
@ -666,7 +667,17 @@ rb_include_module(VALUE klass, VALUE module)
} }
OBJ_INFECT(klass, 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) { while (module) {
int superclass_seen = FALSE; int superclass_seen = FALSE;
@ -696,13 +707,15 @@ rb_include_module(VALUE klass, VALUE module)
skip: skip:
module = RCLASS_SUPER(module); module = RCLASS_SUPER(module);
} }
if (changed) rb_clear_cache();
return changed;
} }
void void
rb_prepend_module(VALUE klass, VALUE module) rb_prepend_module(VALUE klass, VALUE module)
{ {
VALUE p, c, origin; VALUE p, c, origin;
int changed = 0;
rb_frozen_class_p(klass); rb_frozen_class_p(klass);
if (!OBJ_UNTRUSTED(klass)) { if (!OBJ_UNTRUSTED(klass)) {
@ -714,7 +727,7 @@ rb_prepend_module(VALUE klass, VALUE module)
OBJ_INFECT(klass, module); OBJ_INFECT(klass, module);
c = RCLASS_SUPER(klass); c = RCLASS_SUPER(klass);
if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module)) 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)) { for (p = c; p; p = RCLASS_SUPER(p)) {
if (BUILTIN_TYPE(p) == T_ICLASS) { if (BUILTIN_TYPE(p) == T_ICLASS) {
if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) { if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) {
@ -733,9 +746,12 @@ rb_prepend_module(VALUE klass, VALUE module)
c = origin; c = origin;
} }
RCLASS_SUPER(klass) = include_class_new(module, c); RCLASS_SUPER(klass) = include_class_new(module, c);
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) { if (RCLASS_SUPER(module)) {
rb_clear_cache_by_class(klass); 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();
} }
/* /*

View File

@ -1271,6 +1271,15 @@ class TestModule < Test::Unit::TestCase
assert_equal(expected, obj.m1) assert_equal(expected, obj.m1)
end 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 def test_prepend_instance_methods
bug6655 = '[ruby-core:45915]' bug6655 = '[ruby-core:45915]'
assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655) assert_equal(Object.instance_methods, Class.new {prepend Module.new}.instance_methods, bug6655)