Project

General

Profile

Bug #9573 » prepend-future-ancestors-9573.patch

jeremyevans0 (Jeremy Evans), 01/08/2020 08:04 PM

View differences:

class.c
RCLASS_M_TBL(OBJ_WB_UNPROTECT(klass)) =
RCLASS_M_TBL(OBJ_WB_UNPROTECT(module)); /* TODO: unprotected? */
RCLASS_SET_ORIGIN(klass, module == RCLASS_ORIGIN(module) ? klass : RCLASS_ORIGIN(module));
RCLASS_SET_ORIGIN(klass, klass);
if (BUILTIN_TYPE(module) == T_ICLASS) {
module = RBASIC(module)->klass;
}
......
static void ensure_origin(VALUE klass);
struct origin_stack {
VALUE iclass;
VALUE origin_module;
struct origin_stack* next;
};
static int
include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
{
VALUE p, iclass;
int method_changed = 0, constant_changed = 0;
VALUE p, iclass, orig_iclass;
struct origin_stack* orig_stack = NULL;
struct origin_stack* tmp_stack = NULL;
int method_changed = 0, constant_changed = 0, add_subclass;
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);
}
ensure_origin(module);
while (module) {
int superclass_seen = FALSE;
......
iclass = rb_include_class_new(module, RCLASS_SUPER(c));
c = RCLASS_SET_SUPER(c, iclass);
RCLASS_SET_INCLUDER(iclass, klass);
add_subclass = TRUE;
if (module != RCLASS_ORIGIN(module)) {
tmp_stack = orig_stack;
orig_stack = malloc(sizeof(struct origin_stack));
orig_stack->iclass = iclass;
orig_stack->origin_module = RCLASS_ORIGIN(module);
orig_stack->next = tmp_stack;
}
else if (orig_stack && orig_stack->origin_module == module)
{
RCLASS_SET_ORIGIN(orig_stack->iclass, iclass);
tmp_stack = orig_stack;
orig_stack = orig_stack->next;
free(tmp_stack);
add_subclass = FALSE;
}
{
VALUE m = module;
if (BUILTIN_TYPE(m) == T_ICLASS) m = RBASIC(m)->klass;
rb_module_add_to_subclasses_list(m, iclass);
if (add_subclass) rb_module_add_to_subclasses_list(m, iclass);
}
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
......
if (changed) {
rb_vm_check_redefinition_by_prepend(klass);
}
if (RB_TYPE_P(klass, T_MODULE)) {
rb_subclass_entry_t *iclass = RCLASS_EXT(klass)->subclasses;
while (iclass) {
include_modules_at(iclass->klass, iclass->klass, module, FALSE);
iclass = iclass->next;
}
}
}
/*
......
VALUE origin = RCLASS_ORIGIN(mod);
for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
if (p != origin && BUILTIN_TYPE(p) == T_ICLASS) {
if (p != origin && BUILTIN_TYPE(p) == T_ICLASS && !FL_TEST(p, RICLASS_IS_ORIGIN)) {
VALUE m = RBASIC(p)->klass;
if (RB_TYPE_P(m, T_MODULE))
rb_ary_push(ary, m);
......
Check_Type(mod2, T_MODULE);
for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
if (BUILTIN_TYPE(p) == T_ICLASS) {
if (BUILTIN_TYPE(p) == T_ICLASS && !FL_TEST(p, RICLASS_IS_ORIGIN)) {
if (RBASIC(p)->klass == mod2) return Qtrue;
}
}
gc.c
break;
case T_ICLASS:
/* Basically , T_ICLASS shares table with the module */
if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
rb_id_table_free(RCLASS_M_TBL(obj));
}
if (RCLASS_CALLABLE_M_TBL(obj) != NULL) {
rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
}
test/ruby/test_module.rb
m1.include m2
m1.include m3
assert_equal([:m1, :sc, :m2, :m3, :c], o.foo)
m1, m2, m3, sc, o = modules.call
assert_equal([:sc, :c], o.foo)
sc.prepend m1
assert_equal([:m1, :sc, :c], o.foo)
m1.prepend m2
assert_equal([:m2, :m1, :sc, :c], o.foo)
m2.prepend m3
assert_equal([:m3, :m2, :m1, :sc, :c], o.foo)
m1, m2, m3, sc, o = modules.call
sc.include m1
assert_equal([:sc, :m1, :c], o.foo)
sc.prepend m2
assert_equal([:m2, :sc, :m1, :c], o.foo)
sc.prepend m3
assert_equal([:m3, :m2, :sc, :m1, :c], o.foo)
m1, m2, m3, sc, o = modules.call
sc.include m1
assert_equal([:sc, :m1, :c], o.foo)
m2.prepend m3
m1.include m2
assert_equal([:sc, :m1, :m3, :m2, :c], o.foo)
end
def test_included_modules
(2-2/2)