Skip to content

Commit

Permalink
Compiler: fix is_a? for virtual metaclass types (#11121)
Browse files Browse the repository at this point in the history
* Compiler: fix `is_a?` for virtual metaclass types

* Write correct condition for merging two virtual metaclass types
  • Loading branch information
asterite authored Aug 27, 2021
1 parent 8959af1 commit f18b38b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
41 changes: 41 additions & 0 deletions spec/compiler/codegen/is_a_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -815,4 +815,45 @@ describe "Codegen: is_a?" do
Sub.new.is_a?(Mod(Sup))
)).to_b.should be_true
end

it "restricts metaclass against virtual metaclass type" do
run(%(
class A
end
class B < A
end
x = B || A
if x.is_a?(B.class)
1
elsif x.is_a?(A.class)
2
else
3
end
)).to_i.should eq(1)
end

it "restricts virtual metaclass against virtual metaclass type" do
run(%(
class A
end
class B < A
end
class C < B
end
x = B || A
if x.is_a?(B.class)
1
elsif x.is_a?(A.class)
2
else
3
end
)).to_i.should eq(1)
end
end
11 changes: 10 additions & 1 deletion src/compiler/crystal/semantic/type_intersect.cr
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,16 @@ module Crystal
return nil if type1.instance_type.module?

restricted = common_descendent(type1.instance_type, type2.instance_type.base_type)
restricted ? type1 : nil
restricted.try(&.virtual_type.metaclass)
end

def self.common_descendent(type1 : VirtualMetaclassType, type2 : MetaclassType)
common_descendent(type2, type1)
end

def self.common_descendent(type1 : VirtualMetaclassType, type2 : VirtualMetaclassType)
restricted = common_descendent(type1.instance_type, type2.instance_type.base_type)
restricted.try(&.virtual_type.metaclass)
end

def self.common_descendent(type1 : GenericClassInstanceMetaclassType | GenericModuleInstanceMetaclassType, type2 : MetaclassType)
Expand Down

0 comments on commit f18b38b

Please sign in to comment.