From f18b38b01540f45a47aba67e00af1aa55076b75f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Fri, 27 Aug 2021 10:30:57 -0300 Subject: [PATCH] Compiler: fix `is_a?` for virtual metaclass types (#11121) * Compiler: fix `is_a?` for virtual metaclass types * Write correct condition for merging two virtual metaclass types --- spec/compiler/codegen/is_a_spec.cr | 41 +++++++++++++++++++ .../crystal/semantic/type_intersect.cr | 11 ++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/spec/compiler/codegen/is_a_spec.cr b/spec/compiler/codegen/is_a_spec.cr index 46250bc81400..d578f2ef31f2 100644 --- a/spec/compiler/codegen/is_a_spec.cr +++ b/spec/compiler/codegen/is_a_spec.cr @@ -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 diff --git a/src/compiler/crystal/semantic/type_intersect.cr b/src/compiler/crystal/semantic/type_intersect.cr index c05ba59bf08f..93e15267cc69 100644 --- a/src/compiler/crystal/semantic/type_intersect.cr +++ b/src/compiler/crystal/semantic/type_intersect.cr @@ -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)