rb_ivar_defined: handle complex modules

It was assuming only objects can be complex.
This commit is contained in:
Jean Boussier 2023-11-03 10:42:20 +01:00 committed by Jean Boussier
parent 1f1b9b0942
commit 35da6f864a
2 changed files with 60 additions and 1 deletions

View File

@ -345,6 +345,45 @@ class TestShapes < Test::Unit::TestCase
end;
end
def test_run_out_of_shape_instance_variable_defined
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class A
attr_reader :a, :b, :c, :d
def initialize
@a = @b = @c = @d = 1
end
end
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
a = A.new
assert_equal true, a.instance_variable_defined?(:@a)
end;
end
def test_run_out_of_shape_instance_variable_defined_on_module
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
o = Object.new
i = 0
while RubyVM::Shape.shapes_available > 0
o.instance_variable_set(:"@i#{i}", 1)
i += 1
end
module A
@a = @b = @c = @d = 1
end
assert_equal true, A.instance_variable_defined?(:@a)
end;
end
def test_run_out_of_shape_remove_instance_variable
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;

View File

@ -1809,7 +1809,27 @@ rb_ivar_defined(VALUE obj, ID id)
if (SPECIAL_CONST_P(obj)) return Qfalse;
if (rb_shape_obj_too_complex(obj)) {
VALUE idx;
if (!rb_st_lookup(ROBJECT_IV_HASH(obj), id, &idx)) {
st_table *table = NULL;
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
table = (st_table *)RCLASS_IVPTR(obj);
break;
case T_OBJECT:
table = ROBJECT_IV_HASH(obj);
break;
default: {
struct gen_ivtbl *ivtbl;
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
table = ivtbl->as.complex.table;
}
break;
}
}
if (!table || !rb_st_lookup(table, id, &idx)) {
return Qfalse;
}