diff --git a/spec/compiler/semantic/union_spec.cr b/spec/compiler/semantic/union_spec.cr index 61017e7997de..091447a0859d 100644 --- a/spec/compiler/semantic/union_spec.cr +++ b/spec/compiler/semantic/union_spec.cr @@ -314,4 +314,31 @@ describe "Semantic: union" do Union(Foo) )) { types["Foo"].metaclass } end + + it "doesn't run virtual lookup on unbound unions (#9173)" do + assert_type(%( + class Object + def foo + self + end + end + + abstract class Parent + end + + class Child(T) < Parent + @buffer = uninitialized T + + def bar + @buffer.foo + end + end + + class Foo(U) + @x = Child(U | Char).new + end + + Child(Int32).new.as(Parent).bar + )) { int32 } + end end diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr index 21a2e44b40f0..af822c790e24 100644 --- a/src/compiler/crystal/types.cr +++ b/src/compiler/crystal/types.cr @@ -3070,6 +3070,10 @@ module Crystal program.type_merge(new_union_types) || program.no_return end + def unbound? + union_types.any? &.unbound? + end + def all? union_types.all? { |union_type| yield union_type } end