Skip to content

Commit b67711b

Browse files
committed
Fix remove_instance_variable on complex objects
Introduced in: ruby#13159 Now that there is no longer a unique TOO_COMPLEX shape with no children, checking `shape->type == TOO_COMPLEX` is incorrect.
1 parent e3452cf commit b67711b

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

shape.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,13 +618,13 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
618618
// We found a new parent. Create a child of the new parent that
619619
// has the same attributes as this shape.
620620
if (new_parent) {
621-
if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
621+
if (UNLIKELY(rb_shape_too_complex_p(new_parent))) {
622622
return new_parent;
623623
}
624624

625625
bool dont_care;
626626
rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
627-
if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
627+
if (UNLIKELY(rb_shape_too_complex_p(new_child))) {
628628
return new_child;
629629
}
630630

@@ -644,7 +644,7 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
644644
bool
645645
rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE *removed)
646646
{
647-
if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
647+
if (UNLIKELY(rb_shape_too_complex_p(shape))) {
648648
return false;
649649
}
650650

@@ -653,7 +653,7 @@ rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE
653653
if (new_shape) {
654654
RUBY_ASSERT(removed_shape != NULL);
655655

656-
if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
656+
if (UNLIKELY(rb_shape_too_complex_p(new_shape))) {
657657
return false;
658658
}
659659

@@ -797,7 +797,7 @@ static inline rb_shape_t *
797797
shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
798798
{
799799
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
800-
if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
800+
if (UNLIKELY(rb_shape_too_complex_p(shape))) {
801801
return shape;
802802
}
803803

test/ruby/test_shapes.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,9 +788,42 @@ def test_delete_iv_after_complex
788788
assert_equal 3, tc.a3_m # make sure IV is initialized
789789
assert tc.instance_variable_defined?(:@a3)
790790
tc.remove_instance_variable(:@a3)
791+
refute tc.instance_variable_defined?(:@a3)
791792
assert_nil tc.a3
792793
end
793794

795+
def test_delete_iv_after_complex_and_object_id
796+
ensure_complex
797+
798+
tc = TooComplex.new
799+
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
800+
assert_predicate RubyVM::Shape.of(tc), :too_complex?
801+
802+
assert_equal 3, tc.a3_m # make sure IV is initialized
803+
assert tc.instance_variable_defined?(:@a3)
804+
tc.object_id
805+
tc.remove_instance_variable(:@a3)
806+
refute tc.instance_variable_defined?(:@a3)
807+
assert_nil tc.a3
808+
end
809+
810+
def test_delete_iv_after_complex_and_freeze
811+
ensure_complex
812+
813+
tc = TooComplex.new
814+
tc.send("a#{RubyVM::Shape::SHAPE_MAX_VARIATIONS}_m")
815+
assert_predicate RubyVM::Shape.of(tc), :too_complex?
816+
817+
assert_equal 3, tc.a3_m # make sure IV is initialized
818+
assert tc.instance_variable_defined?(:@a3)
819+
tc.freeze
820+
assert_raise FrozenError do
821+
tc.remove_instance_variable(:@a3)
822+
end
823+
assert tc.instance_variable_defined?(:@a3)
824+
assert_equal 3, tc.a3
825+
end
826+
794827
def test_delete_undefined_after_complex
795828
ensure_complex
796829

0 commit comments

Comments
 (0)