Fix class ancestry checks for duped classes

Previously in some when classes were duped (specifically those with a
prepended module), they would not correctly have their "superclasses"
array or depth filled in.

This could cause ancestry checks (like is_a? and Module comparisons) to
return incorrect results.

This happened because rb_mod_init_copy builds origin classes in an order
that doesn't have the super linked list fully connected until it's
finished. This commit fixes the previous issue by calling
rb_class_update_superclasses before returning the cloned class. This is
similar to what's already done in make_metaclass.
This commit is contained in:
John Hawthorn 2022-04-15 15:21:10 -07:00
parent e70e7f4ad3
commit 7950c4eb2d
Notes: git 2022-04-17 03:41:22 +09:00
2 changed files with 22 additions and 0 deletions

View File

@ -567,6 +567,8 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
else {
rb_bug("no origin for class that has origin");
}
rb_class_update_superclasses(clone);
}
return clone;

View File

@ -572,6 +572,26 @@ class TestModule < Test::Unit::TestCase
assert_equal(2, a2.b)
end
def test_ancestry_of_duped_classes
m = Module.new
sc = Class.new
a = Class.new(sc) do
def b; 2 end
prepend m
end
a2 = a.dup.new
assert_kind_of Object, a2
assert_kind_of sc, a2
refute_kind_of a, a2
assert_kind_of m, a2
assert_kind_of Class, a2.class
assert_kind_of sc.singleton_class, a2.class
assert_same sc, a2.class.superclass
end
def test_gc_prepend_chain
assert_separately([], <<-EOS)
10000.times { |i|