summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-07-02 08:06:37 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-07-02 08:06:37 +0000
commitedb1fc4eb2f9b0bd69398362ae40100adfd5577e (patch)
tree48a12ca98a1780f14164a016b6da7c4707b5a2de /class.c
parentbd52bed97be25e8f3344033ac01416349ec8be67 (diff)
prepend: fix mixing with include
* class.c (rb_include_module): include modules after the origin. * class.c (include_modules_at): skip prepended modules. * class.c (rb_prepend_module): now basic.klass in ICLASS refers the old original class/module. [ruby-dev:45868][Bug #6662] * class.c (rb_mod_ancestors): ditto. * vm_method.c (search_method): search method entry from the origin iclass. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36266 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'class.c')
-rw-r--r--class.c54
1 files changed, 16 insertions, 38 deletions
diff --git a/class.c b/class.c
index beeecc7865..d81c093c9c 100644
--- a/class.c
+++ b/class.c
@@ -668,7 +668,9 @@ rb_include_module(VALUE klass, VALUE module)
OBJ_INFECT(klass, module);
- changed = include_modules_at(klass, klass, module);
+ changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module);
+ if (changed < 0)
+ rb_raise(rb_eArgError, "cyclic include detected");
if (changed) rb_clear_cache();
}
@@ -681,8 +683,10 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
while (module) {
int superclass_seen = FALSE;
- if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
- rb_raise(rb_eArgError, "cyclic include detected");
+ if (RCLASS_ORIGIN(module) != module)
+ goto skip;
+ if (RCLASS_M_TBL(klass) && RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
+ return -1;
/* ignore if the module included already in superclasses */
for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) {
switch (BUILTIN_TYPE(p)) {
@@ -699,8 +703,6 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
break;
}
}
- if (c == klass)
- c = RCLASS_ORIGIN(klass);
c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
changed = 1;
@@ -714,7 +716,7 @@ include_modules_at(VALUE klass, VALUE c, VALUE module)
void
rb_prepend_module(VALUE klass, VALUE module)
{
- VALUE p, c, origin;
+ VALUE origin;
int changed = 0;
rb_frozen_class_p(klass);
@@ -725,32 +727,19 @@ rb_prepend_module(VALUE klass, VALUE module)
Check_Type(module, T_MODULE);
OBJ_INFECT(klass, module);
- c = RCLASS_SUPER(klass);
- if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module))
- 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)) {
- rb_raise(rb_eArgError, "already prepended module");
- }
- }
- }
+
origin = RCLASS_ORIGIN(klass);
if (origin == klass) {
- origin = class_alloc(T_ICLASS, rb_cClass);
+ origin = class_alloc(T_ICLASS, klass);
RCLASS_SUPER(origin) = RCLASS_SUPER(klass);
RCLASS_SUPER(klass) = origin;
RCLASS_ORIGIN(klass) = origin;
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL(klass) = 0;
- c = origin;
- }
- RCLASS_SUPER(klass) = include_class_new(module, c);
- 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;
+ changed = include_modules_at(klass, klass, module);
+ if (changed < 0)
+ rb_raise(rb_eArgError, "cyclic prepend detected");
if (changed) rb_clear_cache();
}
@@ -838,25 +827,14 @@ VALUE
rb_mod_ancestors(VALUE mod)
{
VALUE p, ary = rb_ary_new();
- VALUE origin = RCLASS_ORIGIN(mod);
- p = mod;
- if (origin == mod) {
- origin = 0;
- }
- else {
- p = RCLASS_SUPER(p);
- }
- for (; p; p = RCLASS_SUPER(p)) {
+ for (p = mod; p; p = RCLASS_SUPER(p)) {
if (FL_TEST(p, FL_SINGLETON))
continue;
- if (p == origin) {
- rb_ary_push(ary, mod);
- }
- else if (BUILTIN_TYPE(p) == T_ICLASS) {
+ if (BUILTIN_TYPE(p) == T_ICLASS) {
rb_ary_push(ary, RBASIC(p)->klass);
}
- else {
+ else if (p == RCLASS_ORIGIN(p)) {
rb_ary_push(ary, p);
}
}