Project

General

Profile

Bug #22475 ยป fix_prepend_duplicate.patch

naopontan (naoki takaesu), 10/27/2026 09:36 AM

View differences:

class.c
/* During lazy sweeping, the entry could be a dead object that
* has not yet been swept. */
if (!rb_objspace_garbage_object_p(subclass)) {
/* An origin iclass backfilled by a previous prepend is
* registered in the subclasses list only so that method
* cache invalidation can reach it. The module is inserted
* between the includer's iclass and that origin when the
* includer's iclass is visited, so visiting the origin too
* would insert the module a second time. */
if (RICLASS_IS_ORIGIN_P(subclass)) continue;
if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) {
// backfill an origin iclass to handle refinements and future prepends
rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass);
test/ruby/test_module.rb
assert_equal([m, c], c.ancestors[0, 2], "should never duplicate")
end
def test_prepend_to_included_module_multiple_times
m = labeled_module("M")
c = labeled_class("C") {include m}
m0 = labeled_module("M0")
m1 = labeled_module("M1")
m2 = labeled_module("M2")
m.prepend m0
m.prepend m1
m.prepend m2
assert_equal([c, m2, m1, m0, m, Object], c.ancestors[0, 6], "should never duplicate")
base = Module.new {def m; [:base] end}
h = Module.new {include base}
view = Class.new {include h}
p1 = Module.new {def m; [:p1] + super end}
p2 = Module.new {def m; [:p2] + super end}
h.prepend p1
h.prepend p2
assert_equal([:p2, :p1, :base], view.new.m)
end
def test_prepend_in_superclass
m = labeled_module("M")
c1 = labeled_class("C1")
    (1-1/1)