diff --git a/spec/compiler/semantic/tuple_spec.cr b/spec/compiler/semantic/tuple_spec.cr index 56afb4a0dd36..03444c8acd89 100644 --- a/spec/compiler/semantic/tuple_spec.cr +++ b/spec/compiler/semantic/tuple_spec.cr @@ -289,4 +289,15 @@ describe "Semantic: tuples" do ), "tuple too big" end + + it "doesn't unify tuple metaclasses (#5384)" do + assert_type(%( + Tuple(Int32) || Tuple(String) + )) { + union_of( + tuple_of([int32] of Type).metaclass, + tuple_of([string] of Type).metaclass, + ) + } + end end diff --git a/src/compiler/crystal/semantic/type_merge.cr b/src/compiler/crystal/semantic/type_merge.cr index 2ec8d3a9be07..dfc931da14ce 100644 --- a/src/compiler/crystal/semantic/type_merge.cr +++ b/src/compiler/crystal/semantic/type_merge.cr @@ -252,12 +252,14 @@ module Crystal class GenericClassInstanceMetaclassType def common_ancestor(other : MetaclassType | VirtualMetaclassType | GenericClassInstanceMetaclassType) - if instance_type.module? || other.instance_type.module? - nil - else - common = instance_type.common_ancestor(other.instance_type) - common.try &.metaclass - end + # Modules are never unified + return nil if instance_type.module? || other.instance_type.module? + + # Tuple instances might be unified, but never tuple metaclasses + return nil if instance_type.is_a?(TupleInstanceType) || other.instance_type.is_a?(TupleInstanceType) + + common = instance_type.common_ancestor(other.instance_type) + common.try &.metaclass end end