summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/possible-contents.cpp25
-rw-r--r--test/gtest/possible-contents.cpp7
-rw-r--r--test/lit/passes/gufa-refs.wast11
3 files changed, 41 insertions, 2 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 167890d63..836f7570d 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -148,6 +148,14 @@ bool PossibleContents::haveIntersection(const PossibleContents& a,
auto aType = a.getType();
auto bType = b.getType();
+ if (!aType.isRef() || !bType.isRef()) {
+ // At least one is not a reference. The only way they can intersect is if
+ // the type is identical.
+ return aType == bType;
+ }
+
+ // From here on we focus on references.
+
if (aType.isNullable() && bType.isNullable()) {
// Null is possible on both sides. Assume that an intersection can exist,
// but we could be more precise here and check if the types belong to
@@ -156,12 +164,25 @@ bool PossibleContents::haveIntersection(const PossibleContents& a,
return true;
}
- if (a.hasExactType() && b.hasExactType() && a.getType() != b.getType()) {
+ // We ruled out a null on both sides, so at least one is non-nullable. If the
+ // other is a null then no chance for an intersection remains.
+ if (a.isNull() || b.isNull()) {
+ return false;
+ }
+
+ // From here on we focus on references and can ignore the case of null - any
+ // intersection must be of a non-null value, so we can focus on the heap
+ // types.
+ auto aHeapType = aType.getHeapType();
+ auto bHeapType = bType.getHeapType();
+
+ if (a.hasExactType() && b.hasExactType() && aHeapType != bHeapType) {
// The values must be different since their types are different.
return false;
}
- if (!Type::isSubType(aType, bType) && !Type::isSubType(bType, aType)) {
+ if (!HeapType::isSubType(aHeapType, bHeapType) &&
+ !HeapType::isSubType(bHeapType, aHeapType)) {
// No type can appear in both a and b, so the types differ, so the values
// differ.
return false;
diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp
index 1e1f0e5c9..933e220bb 100644
--- a/test/gtest/possible-contents.cpp
+++ b/test/gtest/possible-contents.cpp
@@ -280,9 +280,16 @@ TEST_F(PossibleContentsTest, TestIntersection) {
assertHaveIntersection(exactFuncSignatureType, exactFuncSignatureType);
assertHaveIntersection(i32Zero, i32One); // TODO: this could be inferred false
+ // Exact types only differing by nullability can intersect (not on the null,
+ // but on something else).
+ assertHaveIntersection(exactAnyref, exactNonNullAnyref);
+
// Due to subtyping, an intersection might exist.
assertHaveIntersection(funcGlobal, funcGlobal);
assertHaveIntersection(funcGlobal, exactFuncSignatureType);
+ assertHaveIntersection(nonNullFuncGlobal, exactFuncSignatureType);
+ assertHaveIntersection(funcGlobal, exactNonNullFuncSignatureType);
+ assertHaveIntersection(nonNullFuncGlobal, exactNonNullFuncSignatureType);
// Neither is a subtype of the other, but nulls are possible, so a null can be
// the intersection.
diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast
index 24ebda381..42f1b349d 100644
--- a/test/lit/passes/gufa-refs.wast
+++ b/test/lit/passes/gufa-refs.wast
@@ -2766,6 +2766,9 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref.eq-zero (export "ref.eq-zero")
;; We do not track specific references, so only the types can be used here.
@@ -2791,6 +2794,14 @@
)
)
)
+ (drop
+ (ref.eq
+ (struct.new $struct
+ (i32.const 5)
+ )
+ (ref.null $struct)
+ )
+ )
)
;; CHECK: (func $ref.eq-unknown (type $i32_ref?|$struct|_ref?|$struct|_ref?|$other|_ref|$struct|_ref|$struct|_ref|$other|_=>_none) (param $x i32) (param $struct (ref null $struct)) (param $struct2 (ref null $struct)) (param $other (ref null $other)) (param $nn-struct (ref $struct)) (param $nn-struct2 (ref $struct)) (param $nn-other (ref $other))