@@ -776,11 +776,19 @@ Type Type::getLeastUpperBound(Type a, Type b) {
776776 return Type (elems);
777777 }
778778 if (a.isRef () && b.isRef ()) {
779- if (auto heapType =
780- HeapType::getLeastUpperBound (a.getHeapType (), b.getHeapType ())) {
779+ auto heapTypeA = a.getHeapType ();
780+ auto heapTypeB = b.getHeapType ();
781+ if (auto heapType = HeapType::getLeastUpperBound (heapTypeA, heapTypeB)) {
781782 auto nullability =
782783 (a.isNullable () || b.isNullable ()) ? Nullable : NonNullable;
783- return Type (*heapType, nullability);
784+ auto exactness = (a.isInexact () || b.isInexact ()) ? Inexact : Exact;
785+ // The LUB can only be exact if the heap types are the same or one of them
786+ // is bottom.
787+ if (heapTypeA != heapTypeB && !heapTypeA.isBottom () &&
788+ !heapTypeB.isBottom ()) {
789+ exactness = Inexact;
790+ }
791+ return Type (*heapType, nullability, exactness);
784792 }
785793 }
786794 return Type::none;
@@ -814,6 +822,7 @@ Type Type::getGreatestLowerBound(Type a, Type b) {
814822 }
815823 auto nullability =
816824 (a.isNonNullable () || b.isNonNullable ()) ? NonNullable : Nullable;
825+ auto exactness = (a.isExact () || b.isExact ()) ? Exact : Inexact;
817826 HeapType heapType;
818827 if (HeapType::isSubType (heapA, heapB)) {
819828 heapType = heapA;
@@ -822,7 +831,13 @@ Type Type::getGreatestLowerBound(Type a, Type b) {
822831 } else {
823832 heapType = heapA.getBottom ();
824833 }
825- return Type (heapType, nullability);
834+ // If one of the types is exact, but the GLB heap type is different than its
835+ // heap type, then we must make the GLB heap type bottom.
836+ if ((a.isExact () && heapType != heapA) ||
837+ (b.isExact () && heapType != heapB)) {
838+ heapType = heapA.getBottom ();
839+ }
840+ return Type (heapType, nullability, exactness);
826841}
827842
828843const Type& Type::Iterator::operator *() const {
@@ -1432,14 +1447,24 @@ bool SubTyper::isSubType(Type a, Type b) {
14321447 if (a == Type::unreachable) {
14331448 return true ;
14341449 }
1435- if (a.isRef () && b.isRef ()) {
1436- return (a.isNullable () == b.isNullable () || !a.isNullable ()) &&
1437- isSubType (a.getHeapType (), b.getHeapType ());
1438- }
14391450 if (a.isTuple () && b.isTuple ()) {
14401451 return isSubType (a.getTuple (), b.getTuple ());
14411452 }
1442- return false ;
1453+ if (!a.isRef () || !b.isRef ()) {
1454+ return false ;
1455+ }
1456+ if (a.isNullable () && !b.isNullable ()) {
1457+ return false ;
1458+ }
1459+ if (a.isInexact () && !b.isInexact ()) {
1460+ return false ;
1461+ }
1462+ auto heapTypeA = a.getHeapType ();
1463+ auto heapTypeB = b.getHeapType ();
1464+ if (b.isExact () && !heapTypeA.isBottom ()) {
1465+ return heapTypeA == heapTypeB;
1466+ }
1467+ return isSubType (heapTypeA, heapTypeB);
14431468}
14441469
14451470bool SubTyper::isSubType (HeapType a, HeapType b) {
@@ -1586,44 +1611,69 @@ std::ostream& TypePrinter::print(Type type) {
15861611 } else if (type.isRef ()) {
15871612 auto heapType = type.getHeapType ();
15881613 if (type.isNullable () && heapType.isBasic () && !heapType.isShared ()) {
1614+ if (type.isExact ()) {
1615+ os << " (exact " ;
1616+ }
15891617 // Print shorthands for certain basic heap types.
15901618 switch (heapType.getBasic (Unshared)) {
15911619 case HeapType::ext:
1592- return os << " externref" ;
1620+ os << " externref" ;
1621+ break ;
15931622 case HeapType::func:
1594- return os << " funcref" ;
1623+ os << " funcref" ;
1624+ break ;
15951625 case HeapType::cont:
1596- return os << " contref" ;
1626+ os << " contref" ;
1627+ break ;
15971628 case HeapType::any:
1598- return os << " anyref" ;
1629+ os << " anyref" ;
1630+ break ;
15991631 case HeapType::eq:
1600- return os << " eqref" ;
1632+ os << " eqref" ;
1633+ break ;
16011634 case HeapType::i31:
1602- return os << " i31ref" ;
1635+ os << " i31ref" ;
1636+ break ;
16031637 case HeapType::struct_:
1604- return os << " structref" ;
1638+ os << " structref" ;
1639+ break ;
16051640 case HeapType::array:
1606- return os << " arrayref" ;
1641+ os << " arrayref" ;
1642+ break ;
16071643 case HeapType::exn:
1608- return os << " exnref" ;
1644+ os << " exnref" ;
1645+ break ;
16091646 case HeapType::string:
1610- return os << " stringref" ;
1647+ os << " stringref" ;
1648+ break ;
16111649 case HeapType::none:
1612- return os << " nullref" ;
1650+ os << " nullref" ;
1651+ break ;
16131652 case HeapType::noext:
1614- return os << " nullexternref" ;
1653+ os << " nullexternref" ;
1654+ break ;
16151655 case HeapType::nofunc:
1616- return os << " nullfuncref" ;
1656+ os << " nullfuncref" ;
1657+ break ;
16171658 case HeapType::nocont:
1618- return os << " nullcontref" ;
1659+ os << " nullcontref" ;
1660+ break ;
16191661 case HeapType::noexn:
1620- return os << " nullexnref" ;
1662+ os << " nullexnref" ;
1663+ break ;
16211664 }
1665+ if (type.isExact ()) {
1666+ os << ' )' ;
1667+ }
1668+ return os;
16221669 }
16231670 os << " (ref " ;
16241671 if (type.isNullable ()) {
16251672 os << " null " ;
16261673 }
1674+ if (type.isExact ()) {
1675+ os << " exact " ;
1676+ }
16271677 printHeapTypeName (heapType);
16281678 os << ' )' ;
16291679 } else {
@@ -1851,8 +1901,9 @@ size_t RecGroupHasher::hash(Type type) const {
18511901 return digest;
18521902 }
18531903 assert (type.isRef ());
1854- rehash (digest, type.getNullability ());
1855- rehash (digest, hash (type.getHeapType ()));
1904+ wasm::rehash (digest, type.getNullability ());
1905+ wasm::rehash (digest, type.getExactness ());
1906+ hash_combine (digest, hash (type.getHeapType ()));
18561907 return digest;
18571908}
18581909
@@ -1974,6 +2025,7 @@ bool RecGroupEquator::eq(Type a, Type b) const {
19742025 }
19752026 if (a.isRef () && b.isRef ()) {
19762027 return a.getNullability () == b.getNullability () &&
2028+ a.getExactness () == b.getExactness () &&
19772029 eq (a.getHeapType (), b.getHeapType ());
19782030 }
19792031 return false ;
@@ -2164,8 +2216,10 @@ Type TypeBuilder::getTempTupleType(const Tuple& tuple) {
21642216 return impl->tupleStore .insert (tuple);
21652217}
21662218
2167- Type TypeBuilder::getTempRefType (HeapType type, Nullability nullable) {
2168- return Type (type, nullable);
2219+ Type TypeBuilder::getTempRefType (HeapType type,
2220+ Nullability nullable,
2221+ Exactness exact) {
2222+ return Type (type, nullable, exact);
21692223}
21702224
21712225void TypeBuilder::setSubType (size_t i, std::optional<HeapType> super) {
0 commit comments