Skip to content

Commit

Permalink
Compiler: fix type descendent for union metaclass (#12308)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Jul 24, 2022
1 parent cd2b7d6 commit ee8fca2
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 0 deletions.
11 changes: 11 additions & 0 deletions spec/compiler/codegen/is_a_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -894,4 +894,15 @@ describe "Codegen: is_a?" do
x.is_a?(Union(B, C))
)).to_b.should be_false
end

it "restricts union metaclass to metaclass (#12295)" do
run(%(
x = true ? Union(String | Int32) : String
if x.is_a?(String.class)
1
else
2
end
)).to_i.should eq(2)
end
end
6 changes: 6 additions & 0 deletions src/compiler/crystal/semantic/type_intersect.cr
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ module Crystal
def self.common_descendent(type1 : GenericClassInstanceMetaclassType | GenericModuleInstanceMetaclassType, type2 : MetaclassType | VirtualMetaclassType)
return type1 if type1.instance_type.generic_type.metaclass == type2

# Special case: a GenericInstanceMetaclass with a union type is
# the metaclass of a union type, for example Union(String | Int32).class.
# In that case the intersection of that type with a non-union metaclass
# will never match: it must also be another union type.
return nil if type1.instance_type.is_a?(UnionType)

restricted = common_descendent(type1.instance_type, type2.instance_type)
restricted ? type1 : nil
end
Expand Down

0 comments on commit ee8fca2

Please sign in to comment.