diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2022-01-20 14:21:30 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-20 14:21:30 -0800 |
commit | 5436efcc7ff729e6a16506185bea171e943028c7 (patch) | |
tree | dbb6f4b8a269173f089b83b4c311708361ac13aa | |
parent | 4205846f0f7cc795808d8737fd9a0c2c2e2ab41d (diff) | |
download | binaryen-5436efcc7ff729e6a16506185bea171e943028c7.tar.gz binaryen-5436efcc7ff729e6a16506185bea171e943028c7.tar.bz2 binaryen-5436efcc7ff729e6a16506185bea171e943028c7.zip |
Remove unused `isNominal` field on HeapTypeInfo (#4465)
This field was originally added with the goal of allowing types from multiple
type systems to coexist by determining the type system on a per-type level
rather than globally. This goal was never fully achieved and the `isNominal`
field is not used outside of tests. Now that we are working on implementing the
hybrid isorecursive system, it does not look like having types from multiple
systems coexist will be useful in the near term, so clean up this tech debt.
-rw-r--r-- | src/wasm-type.h | 19 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 4 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 51 | ||||
-rw-r--r-- | test/example/type-builder-nominal-new.cpp | 463 | ||||
-rw-r--r-- | test/example/type-builder-nominal-new.txt | 94 |
6 files changed, 13 insertions, 620 deletions
diff --git a/src/wasm-type.h b/src/wasm-type.h index c80e7cd0b..7d6306ef7 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -385,22 +385,13 @@ public: Array getArray() const; // If there is a nontrivial (i.e. non-basic) nominal supertype, return it, - // else an empty optional. Nominal types (in the sense of isNominal, - // i.e. Milestone 4 nominal types) may always have supertypes and other types - // may have supertypes in `TypeSystem::Nominal` mode but not in - // `TypeSystem::Equirecursive` mode. + // else an empty optional. std::optional<HeapType> getSuperType() const; // Return the depth of this heap type in the nominal type hierarchy, i.e. the // number of supertypes in its supertype chain. size_t getDepth() const; - // Whether this is a nominal type in the sense of being a GC Milestone 4 - // nominal type. Although all non-basic HeapTypes are nominal in - // `TypeSystem::Nominal` mode, this will still return false unless the type is - // specifically constructed as a Milestone 4 nominal type. - bool isNominal() const; - constexpr TypeID getID() const { return id; } constexpr BasicHeapType getBasic() const { assert(isBasic() && "Basic heap type expected"); @@ -605,10 +596,6 @@ struct TypeBuilder { // `j`. Does nothing for equirecursive types. void setSubType(size_t i, size_t j); - // Make this type nominal in the sense of the Milestone 4 GC spec, independent - // of the current TypeSystem configuration. - void setNominal(size_t i); - // Returns all of the newly constructed heap types. May only be called once // all of the heap types have been initialized with `setHeapType`. In nominal // mode, all of the constructed HeapTypes will be fresh and distinct. In @@ -647,10 +634,6 @@ struct TypeBuilder { builder.setSubType(index, other.index); return *this; } - Entry& setNominal() { - builder.setNominal(index); - return *this; - } }; Entry operator[](size_t i) { return Entry{*this, i}; } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 36cb0fd1a..b20269f9b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -224,7 +224,7 @@ void WasmBinaryWriter::writeTypes() { o << U32LEB(indexedTypes.types.size()); for (Index i = 0; i < indexedTypes.types.size(); ++i) { auto type = indexedTypes.types[i]; - bool nominal = type.isNominal() || getTypeSystem() == TypeSystem::Nominal; + bool nominal = getTypeSystem() == TypeSystem::Nominal; BYN_TRACE("write " << type << std::endl); if (type.isSignature()) { o << S32LEB(nominal ? BinaryConsts::EncodedType::FuncExtending @@ -1962,8 +1962,6 @@ void WasmBinaryBuilder::readTypes() { if (form == BinaryConsts::EncodedType::FuncExtending || form == BinaryConsts::EncodedType::StructExtending || form == BinaryConsts::EncodedType::ArrayExtending) { - // TODO: Let the new nominal types coexist with equirecursive types - // builder[i].setNominal(); auto superIndex = getS64LEB(); // TODO: Actually s33 if (superIndex >= 0) { if (size_t(superIndex) >= numTypes) { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 9a537586e..f76db38af 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -876,8 +876,6 @@ void SExpressionWasmBuilder::preParseHeapTypes(Element& module) { } Element* super = nullptr; if (nominal) { - // TODO: Let the new nominal types coexist with equirecursive types - // builder[index].setNominal(); super = def[def.size() - 1]; if (super->dollared()) { // OK diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 738cd6e29..fc42fe230 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -105,8 +105,8 @@ struct HeapTypeInfo { // Otherwise, the type definition tree is still being constructed via the // TypeBuilder interface, so hashing and equality use pointer identity. bool isFinalized = true; - bool isNominal = false; - // In nominal mode, the supertype of this HeapType, if it exists. + // In nominal or isorecursive mode, the supertype of this HeapType, if it + // exists. HeapTypeInfo* supertype = nullptr; enum Kind { BasicKind, @@ -581,7 +581,6 @@ bool TypeInfo::operator==(const TypeInfo& other) const { HeapTypeInfo::HeapTypeInfo(const HeapTypeInfo& other) { kind = other.kind; supertype = other.supertype; - isNominal = other.isNominal; switch (kind) { case BasicKind: new (&basic) auto(other.basic); @@ -690,7 +689,7 @@ private: std::lock_guard<std::recursive_mutex> lock(mutex); // Nominal HeapTypes are always unique, so don't bother deduplicating them. if constexpr (std::is_same_v<Info, HeapTypeInfo>) { - if (info.isNominal || typeSystem == TypeSystem::Nominal) { + if (typeSystem == TypeSystem::Nominal) { return insertNew(); } } @@ -1215,14 +1214,6 @@ size_t HeapType::getDepth() const { return depth; } -bool HeapType::isNominal() const { - if (isBasic()) { - return false; - } else { - return getHeapTypeInfo(*this)->isNominal; - } -} - bool HeapType::isSubType(HeapType left, HeapType right) { // As an optimization, in the common case do not even construct a SubTyper. if (left == right) { @@ -1342,11 +1333,7 @@ bool SubTyper::isSubType(HeapType a, HeapType b) { // Basic HeapTypes are never subtypes of compound HeapTypes. return false; } - // Nominal and structural types are never subtypes of each other. - if (a.isNominal() != b.isNominal()) { - return false; - } - if (a.isNominal() || typeSystem == TypeSystem::Nominal) { + if (typeSystem == TypeSystem::Nominal) { // Subtyping must be declared in a nominal system, not derived from // structure, so we will not recurse. TODO: optimize this search with some // form of caching. @@ -1525,9 +1512,6 @@ HeapType TypeBounder::lub(HeapType a, HeapType b) { if (a.isBasic() || b.isBasic()) { return getBasicLUB(); } - if (a.isNominal() != b.isNominal()) { - return getBasicLUB(); - } HeapTypeInfo* infoA = getHeapTypeInfo(a); HeapTypeInfo* infoB = getHeapTypeInfo(b); @@ -1536,7 +1520,7 @@ HeapType TypeBounder::lub(HeapType a, HeapType b) { return getBasicLUB(); } - if (a.isNominal() || typeSystem == TypeSystem::Nominal) { + if (typeSystem == TypeSystem::Nominal) { // Walk up the subtype tree to find the LUB. Ascend the tree from both `a` // and `b` in lockstep. The first type we see for a second time must be the // LUB because there are no cycles and the only way to encounter a type @@ -1971,15 +1955,13 @@ size_t FiniteShapeHasher::hash(const TypeInfo& info) { } size_t FiniteShapeHasher::hash(const HeapTypeInfo& info) { - size_t digest = wasm::hash(info.isNominal); - if (info.isNominal || getTypeSystem() == TypeSystem::Nominal) { - rehash(digest, uintptr_t(&info)); - return digest; + if (getTypeSystem() == TypeSystem::Nominal) { + return wasm::hash(uintptr_t(&info)); } // If the HeapTypeInfo is not finalized, then it is mutable and its shape // might change in the future. In that case, fall back to pointer identity to // keep the hash consistent until all the TypeBuilder's types are finalized. - digest = wasm::hash(info.isFinalized); + size_t digest = wasm::hash(info.isFinalized); if (!info.isFinalized) { rehash(digest, uintptr_t(&info)); return digest; @@ -2094,9 +2076,7 @@ bool FiniteShapeEquator::eq(const TypeInfo& a, const TypeInfo& b) { } bool FiniteShapeEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) { - if (a.isNominal != b.isNominal) { - return false; - } else if (a.isNominal || getTypeSystem() == TypeSystem::Nominal) { + if (getTypeSystem() == TypeSystem::Nominal) { return &a == &b; } if (a.isFinalized != b.isFinalized) { @@ -2264,7 +2244,6 @@ struct TypeBuilder::Impl { } void set(HeapTypeInfo&& hti) { hti.supertype = info->supertype; - hti.isNominal = info->isNominal; *info = std::move(hti); info->isTemp = true; info->isFinalized = false; @@ -2359,11 +2338,6 @@ void TypeBuilder::setSubType(size_t i, size_t j) { sub->supertype = super; } -void TypeBuilder::setNominal(size_t i) { - assert(i < size() && "index out of bounds"); - impl->entries[i].info->isNominal = true; -} - namespace { // Helper for TypeBuilder::build() that keeps track of temporary types and @@ -3036,9 +3010,7 @@ void globallyCanonicalize(CanonicalizationState& state) { void canonicalizeEquirecursive(CanonicalizationState& state) { // Equirecursive types always have null supertypes. for (auto& info : state.newInfos) { - if (!info->isNominal) { - info->supertype = nullptr; - } + info->supertype = nullptr; } #if TIME_CANONICALIZATION @@ -3219,8 +3191,7 @@ std::vector<HeapType> TypeBuilder::build() { // Note built signature types. See comment in `HeapType::HeapType(Signature)`. for (auto type : state.results) { - if (type.isSignature() && - (type.isNominal() || getTypeSystem() == TypeSystem::Nominal)) { + if (type.isSignature() && (getTypeSystem() == TypeSystem::Nominal)) { nominalSignatureCache.insertType(type); } } diff --git a/test/example/type-builder-nominal-new.cpp b/test/example/type-builder-nominal-new.cpp deleted file mode 100644 index a8bef1eca..000000000 --- a/test/example/type-builder-nominal-new.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include <cassert> -#include <iostream> - -#include "wasm-type.h" - -/* This file is identical to type-builder-nominal.cpp, except that instead of - * setting the global type system to be nominal, it instead individually sets - * each type to be nominal. test_signatures has been removed because the new - * nominal types are never considered canonical, so that test was - * meaningless. */ - -using namespace wasm; - -static void makeNominal(TypeBuilder& builder) { - for (size_t i = 0; i < builder.size(); ++i) { - builder[i].setNominal(); - } -} - -// Construct Signature, Struct, and Array heap types using undefined types. -void test_builder() { - std::cout << ";; Test TypeBuilder\n"; - - // (type $sig (func (param (ref $struct)) (result (ref $array) i32))) - // (type $struct (struct (field (ref null $array) (mut rtt 0 $array)))) - // (type $array (array (mut externref))) - - TypeBuilder builder; - assert(builder.size() == 0); - builder.grow(3); - assert(builder.size() == 3); - - makeNominal(builder); - - Type refSig = builder.getTempRefType(builder[0], NonNullable); - Type refStruct = builder.getTempRefType(builder[1], NonNullable); - Type refArray = builder.getTempRefType(builder[2], NonNullable); - Type refNullArray = builder.getTempRefType(builder[2], Nullable); - Type rttArray = builder.getTempRttType(Rtt(0, builder[2])); - Type refNullExt(HeapType::ext, Nullable); - - Signature sig(refStruct, builder.getTempTupleType({refArray, Type::i32})); - Struct struct_({Field(refNullArray, Immutable), Field(rttArray, Mutable)}); - Array array(Field(refNullExt, Mutable)); - - std::cout << "Before setting heap types:\n"; - std::cout << "(ref $sig) => " << refSig << "\n"; - std::cout << "(ref $struct) => " << refStruct << "\n"; - std::cout << "(ref $array) => " << refArray << "\n"; - std::cout << "(ref null $array) => " << refNullArray << "\n"; - std::cout << "(rtt 0 $array) => " << rttArray << "\n\n"; - - builder[0] = sig; - builder[1] = struct_; - builder[2] = array; - - std::cout << "After setting heap types:\n"; - std::cout << "(ref $sig) => " << refSig << "\n"; - std::cout << "(ref $struct) => " << refStruct << "\n"; - std::cout << "(ref $array) => " << refArray << "\n"; - std::cout << "(ref null $array) => " << refNullArray << "\n"; - std::cout << "(rtt 0 $array) => " << rttArray << "\n\n"; - - std::vector<HeapType> built = builder.build(); - - Type newRefSig = Type(built[0], NonNullable); - Type newRefStruct = Type(built[1], NonNullable); - Type newRefArray = Type(built[2], NonNullable); - Type newRefNullArray = Type(built[2], Nullable); - Type newRttArray = Type(Rtt(0, built[2])); - - std::cout << "After building types:\n"; - std::cout << "(ref $sig) => " << newRefSig << "\n"; - std::cout << "(ref $struct) => " << newRefStruct << "\n"; - std::cout << "(ref $array) => " << newRefArray << "\n"; - std::cout << "(ref null $array) => " << newRefNullArray << "\n"; - std::cout << "(rtt 0 $array) => " << newRttArray << "\n\n"; -} - -// Check that the builder works when there are duplicate definitions -void test_canonicalization() { - std::cout << ";; Test canonicalization\n"; - - // (type $struct (struct (field (ref null $sig) (ref null $sig)))) - // (type $sig (func)) - HeapType sig = Signature(Type::none, Type::none); - HeapType struct_ = Struct({Field(Type(sig, Nullable), Immutable), - Field(Type(sig, Nullable), Immutable)}); - - TypeBuilder builder(4); - makeNominal(builder); - - Type tempSigRef1 = builder.getTempRefType(builder[2], Nullable); - Type tempSigRef2 = builder.getTempRefType(builder[3], Nullable); - - assert(tempSigRef1 != tempSigRef2); - assert(tempSigRef1 != Type(sig, Nullable)); - assert(tempSigRef2 != Type(sig, Nullable)); - - builder[0] = - Struct({Field(tempSigRef1, Immutable), Field(tempSigRef1, Immutable)}); - builder[1] = - Struct({Field(tempSigRef2, Immutable), Field(tempSigRef2, Immutable)}); - builder[2] = Signature(Type::none, Type::none); - builder[3] = Signature(Type::none, Type::none); - - std::vector<HeapType> built = builder.build(); - - assert(built[0] != struct_); - assert(built[1] != struct_); - assert(built[0] != built[1]); - assert(built[2] != sig); - assert(built[3] != sig); - assert(built[2] != built[3]); -} - -// Check that defined basic HeapTypes are handled correctly. -void test_basic() { - std::cout << ";; Test basic\n"; - - TypeBuilder builder(6); - makeNominal(builder); - - Type anyref = builder.getTempRefType(builder[4], Nullable); - Type i31ref = builder.getTempRefType(builder[5], NonNullable); - - builder[0] = Signature(Type::anyref, Type::i31ref); - builder[1] = Signature(anyref, Type::i31ref); - builder[2] = Signature(Type::anyref, i31ref); - builder[3] = Signature(anyref, i31ref); - builder[4] = HeapType::any; - builder[5] = HeapType::i31; - - std::vector<HeapType> built = builder.build(); - - assert(built[0].getSignature() == Signature(Type::anyref, Type::i31ref)); - assert(built[1].getSignature() == built[0].getSignature()); - assert(built[2].getSignature() == built[1].getSignature()); - assert(built[3].getSignature() == built[2].getSignature()); - assert(built[4] == HeapType::any); - assert(built[5] == HeapType::i31); -} - -void test_recursive() { - std::cout << ";; Test recursive types\n"; - - { - // Trivial recursion - std::vector<HeapType> built; - { - TypeBuilder builder(1); - makeNominal(builder); - - Type temp = builder.getTempRefType(builder[0], Nullable); - builder[0] = Signature(Type::none, temp); - built = builder.build(); - } - std::cout << built[0] << "\n\n"; - assert(built[0] == built[0].getSignature().results.getHeapType()); - assert(Type(built[0], Nullable) == built[0].getSignature().results); - } - - { - // Mutual recursion - std::vector<HeapType> built; - { - TypeBuilder builder(2); - makeNominal(builder); - - Type temp0 = builder.getTempRefType(builder[0], Nullable); - Type temp1 = builder.getTempRefType(builder[1], Nullable); - builder[0] = Signature(Type::none, temp1); - builder[1] = Signature(Type::none, temp0); - built = builder.build(); - } - std::cout << built[0] << "\n"; - std::cout << built[1] << "\n\n"; - assert(built[0].getSignature().results.getHeapType() == built[1]); - assert(built[1].getSignature().results.getHeapType() == built[0]); - assert(built[0] != built[1]); - } - - { - // A longer chain of recursion - std::vector<HeapType> built; - { - TypeBuilder builder(5); - makeNominal(builder); - - Type temp0 = builder.getTempRefType(builder[0], Nullable); - Type temp1 = builder.getTempRefType(builder[1], Nullable); - Type temp2 = builder.getTempRefType(builder[2], Nullable); - Type temp3 = builder.getTempRefType(builder[3], Nullable); - Type temp4 = builder.getTempRefType(builder[4], Nullable); - builder[0] = Signature(Type::none, temp1); - builder[1] = Signature(Type::none, temp2); - builder[2] = Signature(Type::none, temp3); - builder[3] = Signature(Type::none, temp4); - builder[4] = Signature(Type::none, temp0); - built = builder.build(); - } - std::cout << built[0] << "\n"; - std::cout << built[1] << "\n"; - std::cout << built[2] << "\n"; - std::cout << built[3] << "\n"; - std::cout << built[4] << "\n\n"; - assert(built[0].getSignature().results.getHeapType() == built[1]); - assert(built[1].getSignature().results.getHeapType() == built[2]); - assert(built[2].getSignature().results.getHeapType() == built[3]); - assert(built[3].getSignature().results.getHeapType() == built[4]); - assert(built[4].getSignature().results.getHeapType() == built[0]); - assert(built[0] != built[1]); - assert(built[0] != built[2]); - assert(built[0] != built[3]); - assert(built[0] != built[4]); - assert(built[1] != built[2]); - assert(built[1] != built[3]); - assert(built[1] != built[4]); - assert(built[2] != built[3]); - assert(built[2] != built[4]); - assert(built[3] != built[4]); - } - - { - // Check canonicalization for non-recursive parents and children of - // recursive HeapTypes. - std::vector<HeapType> built; - { - TypeBuilder builder(6); - makeNominal(builder); - - Type temp0 = builder.getTempRefType(builder[0], Nullable); - Type temp1 = builder.getTempRefType(builder[1], Nullable); - Type temp2 = builder.getTempRefType(builder[2], Nullable); - Type temp3 = builder.getTempRefType(builder[3], Nullable); - Type tuple0_2 = builder.getTempTupleType({temp0, temp2}); - Type tuple1_3 = builder.getTempTupleType({temp1, temp3}); - builder[0] = Signature(Type::none, tuple0_2); - builder[1] = Signature(Type::none, tuple1_3); - builder[2] = Signature(); - builder[3] = Signature(); - builder[4] = Signature(Type::none, temp0); - builder[5] = Signature(Type::none, temp1); - built = builder.build(); - } - std::cout << built[0] << "\n"; - std::cout << built[1] << "\n"; - std::cout << built[2] << "\n"; - std::cout << built[3] << "\n"; - std::cout << built[4] << "\n"; - std::cout << built[5] << "\n\n"; - assert(built[0] != built[1]); - assert(built[2] != built[3]); - assert(built[4] != built[5]); - assert(built[4].getSignature().results.getHeapType() == built[0]); - assert(built[5].getSignature().results.getHeapType() == built[1]); - assert(built[0].getSignature().results == - Type({Type(built[0], Nullable), Type(built[2], Nullable)})); - assert(built[1].getSignature().results == - Type({Type(built[1], Nullable), Type(built[3], Nullable)})); - } - - { - // Folded and unfolded - std::vector<HeapType> built; - { - TypeBuilder builder(2); - makeNominal(builder); - - Type temp0 = builder.getTempRefType(builder[0], Nullable); - builder[0] = Signature(Type::none, temp0); - builder[1] = Signature(Type::none, temp0); - built = builder.build(); - } - std::cout << built[0] << "\n"; - std::cout << built[1] << "\n\n"; - assert(built[0].getSignature().results.getHeapType() == built[0]); - assert(built[1].getSignature().results.getHeapType() == built[0]); - assert(built[0] != built[1]); - } -} - -void test_subtypes() { - std::cout << ";; Test subtyping\n"; - - auto LUB = [&](HeapType a, HeapType b) { - Type refA = Type(a, Nullable); - Type refB = Type(b, Nullable); - Type lubAB = Type::getLeastUpperBound(refA, refB); - Type lubBA = Type::getLeastUpperBound(refB, refA); - assert(lubAB == lubBA); - assert(lubAB != Type::none); - HeapType lub = lubAB.getHeapType(); - assert(Type::hasLeastUpperBound(refA, refB)); - assert(Type::hasLeastUpperBound(refB, refA)); - assert(Type::isSubType(refA, lubAB)); - assert(Type::isSubType(refB, lubAB)); - assert(HeapType::isSubType(a, lub)); - assert(HeapType::isSubType(b, lub)); - assert(lub == a || !HeapType::isSubType(lub, a)); - assert(lub == b || !HeapType::isSubType(lub, b)); - return lub; - }; - - { - // Basic Types - for (auto other : {HeapType::func, - HeapType::ext, - HeapType::any, - HeapType::eq, - HeapType::i31, - HeapType::data}) { - assert(LUB(HeapType::any, other) == HeapType::any); - } - assert(LUB(HeapType::eq, HeapType::func) == HeapType::any); - assert(LUB(HeapType::i31, HeapType::data) == HeapType::eq); - } - - { - // Identity - std::vector<HeapType> built; - { - TypeBuilder builder(3); - makeNominal(builder); - - builder[0] = Signature(Type::none, Type::none); - builder[1] = Struct{}; - builder[2] = Array(Field(Type::i32, Mutable)); - built = builder.build(); - } - assert(LUB(built[0], built[0]) == built[0]); - assert(LUB(built[1], built[1]) == built[1]); - assert(LUB(built[2], built[2]) == built[2]); - } - - { - // No subtype declarations mean no subtypes - std::vector<HeapType> built; - { - TypeBuilder builder(5); - makeNominal(builder); - - Type structRef0 = builder.getTempRefType(builder[0], Nullable); - Type structRef1 = builder.getTempRefType(builder[1], Nullable); - builder[0] = Struct{}; - builder[1] = Struct{}; - builder[2] = Signature(Type::none, Type::anyref); - builder[3] = Signature(Type::none, structRef0); - builder[4] = Signature(Type::none, structRef1); - built = builder.build(); - } - assert(LUB(built[0], built[1]) == HeapType::data); - assert(LUB(built[2], built[3]) == HeapType::func); - assert(LUB(built[2], built[4]) == HeapType::func); - } - - { - // Subtype declarations, but still no subtypes - std::vector<HeapType> built; - { - TypeBuilder builder(3); - makeNominal(builder); - - builder[0].subTypeOf(builder[1]); - builder[0] = Struct{}; - builder[1] = Struct{}; - builder[2] = Struct{}; - built = builder.build(); - } - assert(LUB(built[0], built[2]) == HeapType::data); - } - - { - // Subtyping of identical types - std::vector<HeapType> built; - { - TypeBuilder builder(6); - makeNominal(builder); - - builder[0].subTypeOf(builder[1]); - builder[2].subTypeOf(builder[3]); - builder[4].subTypeOf(builder[5]); - builder[0] = - Struct({Field(Type::i32, Mutable), Field(Type::anyref, Mutable)}); - builder[1] = - Struct({Field(Type::i32, Mutable), Field(Type::anyref, Mutable)}); - builder[2] = Signature(Type::i32, Type::anyref); - builder[3] = Signature(Type::i32, Type::anyref); - builder[4] = Array(Field(Type::i32, Mutable)); - builder[5] = Array(Field(Type::i32, Mutable)); - built = builder.build(); - } - assert(LUB(built[0], built[1]) == built[1]); - assert(LUB(built[2], built[3]) == built[3]); - assert(LUB(built[4], built[5]) == built[5]); - } - - { - // Width subtyping - std::vector<HeapType> built; - { - TypeBuilder builder(2); - makeNominal(builder); - - builder[0] = Struct({Field(Type::i32, Immutable)}); - builder[1] = - Struct({Field(Type::i32, Immutable), Field(Type::i32, Immutable)}); - builder[1].subTypeOf(builder[0]); - built = builder.build(); - } - assert(LUB(built[1], built[0]) == built[0]); - } - - { - // Depth subtyping - std::vector<HeapType> built; - { - TypeBuilder builder(2); - makeNominal(builder); - - builder[0] = Struct({Field(Type::anyref, Immutable)}); - builder[1] = Struct({Field(Type::funcref, Immutable)}); - builder[1].subTypeOf(builder[0]); - built = builder.build(); - } - assert(LUB(built[1], built[0]) == built[0]); - } - - { - // Mutually recursive subtyping - std::vector<HeapType> built; - { - TypeBuilder builder(4); - makeNominal(builder); - - Type a = builder.getTempRefType(builder[0], Nullable); - Type b = builder.getTempRefType(builder[1], Nullable); - Type c = builder.getTempRefType(builder[2], Nullable); - Type d = builder.getTempRefType(builder[3], Nullable); - builder[1].subTypeOf(builder[0]); - builder[3].subTypeOf(builder[2]); - builder[0] = Struct({Field(c, Immutable)}); - builder[1] = Struct({Field(d, Immutable)}); - builder[2] = Struct({Field(a, Immutable)}); - builder[3] = Struct({Field(b, Immutable)}); - built = builder.build(); - } - assert(LUB(built[0], built[1]) == built[0]); - assert(LUB(built[2], built[3]) == built[2]); - } -} - -int main() { - // Run the tests twice to ensure things still work when the global stores are - // already populated. - for (size_t i = 0; i < 2; ++i) { - test_builder(); - test_canonicalization(); - test_basic(); - test_recursive(); - test_subtypes(); - } -} diff --git a/test/example/type-builder-nominal-new.txt b/test/example/type-builder-nominal-new.txt deleted file mode 100644 index 6f0218e54..000000000 --- a/test/example/type-builder-nominal-new.txt +++ /dev/null @@ -1,94 +0,0 @@ -;; Test TypeBuilder -Before setting heap types: -(ref $sig) => [T](ref [T](func)) -(ref $struct) => [T](ref [T](func)) -(ref $array) => [T](ref [T](func)) -(ref null $array) => [T](ref null [T](func)) -(rtt 0 $array) => [T](rtt 0 [T](func)) - -After setting heap types: -(ref $sig) => [T](ref [T](func (param [T](ref [T](struct (field [T](ref null [T](array (mut externref))) (mut [T](rtt 0 [T](array (mut externref)))))))) (result [T](ref [T](array (mut externref))) i32))) -(ref $struct) => [T](ref [T](struct (field [T](ref null [T](array (mut externref))) (mut [T](rtt 0 [T](array (mut externref))))))) -(ref $array) => [T](ref [T](array (mut externref))) -(ref null $array) => [T](ref null [T](array (mut externref))) -(rtt 0 $array) => [T](rtt 0 [T](array (mut externref))) - -After building types: -(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32))) -(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref))))))) -(ref $array) => (ref (array (mut externref))) -(ref null $array) => (ref null (array (mut externref))) -(rtt 0 $array) => (rtt 0 (array (mut externref))) - -;; Test canonicalization -;; Test basic -;; Test recursive types -(func (result (ref null ...1))) - -(func (result (ref null (func (result (ref null ...3)))))) -(func (result (ref null (func (result (ref null ...3)))))) - -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) - -(func (result (ref null ...1) (ref null (func)))) -(func (result (ref null ...1) (ref null (func)))) -(func) -(func) -(func (result (ref null (func (result ...1 (ref null (func))))))) -(func (result (ref null (func (result ...1 (ref null (func))))))) - -(func (result (ref null ...1))) -(func (result (ref null (func (result ...1))))) - -;; Test subtyping -;; Test TypeBuilder -Before setting heap types: -(ref $sig) => [T](ref [T](func)) -(ref $struct) => [T](ref [T](func)) -(ref $array) => [T](ref [T](func)) -(ref null $array) => [T](ref null [T](func)) -(rtt 0 $array) => [T](rtt 0 [T](func)) - -After setting heap types: -(ref $sig) => [T](ref [T](func (param [T](ref [T](struct (field [T](ref null [T](array (mut externref))) (mut [T](rtt 0 [T](array (mut externref)))))))) (result [T](ref [T](array (mut externref))) i32))) -(ref $struct) => [T](ref [T](struct (field [T](ref null [T](array (mut externref))) (mut [T](rtt 0 [T](array (mut externref))))))) -(ref $array) => [T](ref [T](array (mut externref))) -(ref null $array) => [T](ref null [T](array (mut externref))) -(rtt 0 $array) => [T](rtt 0 [T](array (mut externref))) - -After building types: -(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32))) -(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref))))))) -(ref $array) => (ref (array (mut externref))) -(ref null $array) => (ref null (array (mut externref))) -(rtt 0 $array) => (rtt 0 (array (mut externref))) - -;; Test canonicalization -;; Test basic -;; Test recursive types -(func (result (ref null ...1))) - -(func (result (ref null (func (result (ref null ...3)))))) -(func (result (ref null (func (result (ref null ...3)))))) - -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) -(func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null (func (result (ref null ...9))))))))))))))) - -(func (result (ref null ...1) (ref null (func)))) -(func (result (ref null ...1) (ref null (func)))) -(func) -(func) -(func (result (ref null (func (result ...1 (ref null (func))))))) -(func (result (ref null (func (result ...1 (ref null (func))))))) - -(func (result (ref null ...1))) -(func (result (ref null (func (result ...1))))) - -;; Test subtyping |