summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-04-17 09:57:05 -0700
committerGitHub <noreply@github.com>2023-04-17 09:57:05 -0700
commitaddbc66ff7a42ed3b94c05e188db936b36968c9f (patch)
treea3d151ac09209899f493fefa14654c29e8916e8e
parentcbe637f6c1517c9fb501453ba3774e73f12489d8 (diff)
downloadbinaryen-addbc66ff7a42ed3b94c05e188db936b36968c9f.tar.gz
binaryen-addbc66ff7a42ed3b94c05e188db936b36968c9f.tar.bz2
binaryen-addbc66ff7a42ed3b94c05e188db936b36968c9f.zip
Remove the nominal type system (#5672)
And since the only type system left is the standard isorecursive type system, remove `TypeSystem` and its associated APIs entirely. Delete a few tests that only made sense under the isorecursive type system.
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/binaryen-c.cpp15
-rw-r--r--src/binaryen-c.h9
-rw-r--r--src/ir/module-utils.cpp28
-rw-r--r--src/tools/fuzzing/heap-types.cpp39
-rw-r--r--src/tools/tool-options.h4
-rw-r--r--src/tools/wasm-fuzz-types.cpp56
-rw-r--r--src/wasm-type.h11
-rw-r--r--src/wasm/wasm-binary.cpp32
-rw-r--r--src/wasm/wasm-type.cpp161
-rw-r--r--test/example/c-api-kitchen-sink.c19
-rw-r--r--test/example/c-api-kitchen-sink.txt2
-rw-r--r--test/example/type-builder-nominal.cpp428
-rw-r--r--test/example/type-builder-nominal.txt102
-rw-r--r--test/gtest/possible-contents.cpp6
-rw-r--r--test/gtest/type-builder.cpp100
-rw-r--r--test/gtest/type-test.h17
17 files changed, 94 insertions, 941 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2d76ec92..6bad6aa3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,9 +17,9 @@ Current Trunk
- Some C and JS API functions now refer to data and element segments by name
instead of index.
-- The --nominal and --hybrid command line options have been removed. The only
- supported type system is now the standard isorecursive (i.e. hybrid) type
- system.
+- The --nominal and --hybrid command line options and related API functions have
+ been removed. The only supported type system is now the standard isorecursive
+ (i.e. hybrid) type system.
v112
----
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 01f14f924..b23d53ad6 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -406,21 +406,6 @@ BinaryenType BinaryenTypeFromHeapType(BinaryenHeapType heapType,
.getID();
}
-// TypeSystem
-
-BinaryenTypeSystem BinaryenTypeSystemNominal() {
- return static_cast<BinaryenTypeSystem>(TypeSystem::Nominal);
-}
-BinaryenTypeSystem BinaryenTypeSystemIsorecursive() {
- return static_cast<BinaryenTypeSystem>(TypeSystem::Isorecursive);
-}
-BinaryenTypeSystem BinaryenGetTypeSystem() {
- return BinaryenTypeSystem(getTypeSystem());
-}
-void BinaryenSetTypeSystem(BinaryenTypeSystem typeSystem) {
- setTypeSystem(TypeSystem(typeSystem));
-}
-
// Expression ids
BinaryenExpressionId BinaryenInvalidId(void) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index afbc13782..d05bdf33b 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -188,15 +188,6 @@ BINARYEN_API bool BinaryenTypeIsNullable(BinaryenType type);
BINARYEN_API BinaryenType BinaryenTypeFromHeapType(BinaryenHeapType heapType,
bool nullable);
-// TypeSystem
-
-typedef uint32_t BinaryenTypeSystem;
-
-BINARYEN_API BinaryenTypeSystem BinaryenTypeSystemNominal(void);
-BINARYEN_API BinaryenTypeSystem BinaryenTypeSystemIsorecursive(void);
-BINARYEN_API BinaryenTypeSystem BinaryenGetTypeSystem(void);
-BINARYEN_API void BinaryenSetTypeSystem(BinaryenTypeSystem typeSystem);
-
// Expression ids (call to get the value of each; you can cache them)
typedef uint32_t BinaryenExpressionId;
diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp
index efab9e20b..ce6fadda7 100644
--- a/src/ir/module-utils.cpp
+++ b/src/ir/module-utils.cpp
@@ -345,7 +345,6 @@ std::vector<HeapType> getPrivateHeapTypes(Module& wasm) {
}
IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
- TypeSystem system = getTypeSystem();
Counts counts = getHeapTypeCounts(wasm);
// Types have to be arranged into topologically ordered recursion groups.
@@ -385,32 +384,21 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) {
// Update the reference count.
info.useCount += counts.at(type);
// Collect predecessor groups.
- switch (system) {
- case TypeSystem::Isorecursive:
- for (auto child : type.getReferencedHeapTypes()) {
- if (!child.isBasic()) {
- RecGroup otherGroup = child.getRecGroup();
- if (otherGroup != group) {
- info.preds.insert(otherGroup);
- }
- }
- }
- break;
- case TypeSystem::Nominal:
- if (auto super = type.getSuperType()) {
- info.preds.insert(super->getRecGroup());
+ for (auto child : type.getReferencedHeapTypes()) {
+ if (!child.isBasic()) {
+ RecGroup otherGroup = child.getRecGroup();
+ if (otherGroup != group) {
+ info.preds.insert(otherGroup);
}
- break;
+ }
}
}
// Fix up the use counts to be averages to ensure groups are used comensurate
// with the amount of index space they occupy. Skip this for nominal types
// since their internal group size is always 1.
- if (system != TypeSystem::Nominal) {
- for (auto& [group, info] : groupInfos) {
- info.useCount /= group.size();
- }
+ for (auto& [group, info] : groupInfos) {
+ info.useCount /= group.size();
}
// Sort the predecessors so the most used will be visited first.
diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp
index 24054572d..e58c7f51d 100644
--- a/src/tools/fuzzing/heap-types.cpp
+++ b/src/tools/fuzzing/heap-types.cpp
@@ -65,8 +65,7 @@ struct HeapTypeGeneratorImpl {
// Set up the subtype relationships. Start with some number of root types,
// then after that start creating subtypes of existing types. Determine the
// top-level kind of each type in advance so that we can appropriately use
- // types we haven't constructed yet. For simplicity, always choose a
- // supertype to bea previous type, which is valid in all type systems.
+ // types we haven't constructed yet.
typeKinds.reserve(builder.size());
supertypeIndices.reserve(builder.size());
Index numRoots = 1 + rand.upTo(builder.size());
@@ -90,31 +89,23 @@ struct HeapTypeGeneratorImpl {
// Initialize the recursion groups.
recGroupEnds.reserve(builder.size());
- if (getTypeSystem() != TypeSystem::Isorecursive) {
- // Recursion groups don't matter and we can choose children as though we
- // had a single large recursion group.
- for (Index i = 0; i < builder.size(); ++i) {
- recGroupEnds.push_back(builder.size());
- }
- } else {
- // We are using isorecursive types, so create groups. Choose an expected
- // group size uniformly at random, then create groups with random sizes on
- // a geometric distribution based on that expected size.
- size_t expectedSize = 1 + rand.upTo(builder.size());
- Index groupStart = 0;
- for (Index i = 0; i < builder.size(); ++i) {
- if (i == builder.size() - 1 || rand.oneIn(expectedSize)) {
- // End the old group and create a new group.
- Index newGroupStart = i + 1;
- builder.createRecGroup(groupStart, newGroupStart - groupStart);
- for (Index j = groupStart; j < newGroupStart; ++j) {
- recGroupEnds.push_back(newGroupStart);
- }
- groupStart = newGroupStart;
+ // Create isorecursive recursion groups. Choose an expected group size
+ // uniformly at random, then create groups with random sizes on a geometric
+ // distribution based on that expected size.
+ size_t expectedSize = 1 + rand.upTo(builder.size());
+ Index groupStart = 0;
+ for (Index i = 0; i < builder.size(); ++i) {
+ if (i == builder.size() - 1 || rand.oneIn(expectedSize)) {
+ // End the old group and create a new group.
+ Index newGroupStart = i + 1;
+ builder.createRecGroup(groupStart, newGroupStart - groupStart);
+ for (Index j = groupStart; j < newGroupStart; ++j) {
+ recGroupEnds.push_back(newGroupStart);
}
+ groupStart = newGroupStart;
}
- assert(recGroupEnds.size() == builder.size());
}
+ assert(recGroupEnds.size() == builder.size());
// Create the heap types.
for (; index < builder.size(); ++index) {
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index 4e9d85d00..a6e57a76e 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -182,10 +182,6 @@ struct ToolOptions : public Options {
void applyFeatures(Module& module) const {
module.features.enable(enabledFeatures);
module.features.disable(disabledFeatures);
- // Non-default type systems only make sense with GC enabled.
- if (!module.features.hasGC() && getTypeSystem() == TypeSystem::Nominal) {
- Fatal() << "Nominal typing is only allowed when GC is enabled";
- }
}
private:
diff --git a/src/tools/wasm-fuzz-types.cpp b/src/tools/wasm-fuzz-types.cpp
index ce393d133..0dc9f9d17 100644
--- a/src/tools/wasm-fuzz-types.cpp
+++ b/src/tools/wasm-fuzz-types.cpp
@@ -228,11 +228,6 @@ void Fuzzer::checkCanonicalization() {
// Check that structural canonicalization is working correctly by building the
// types again, choosing randomly between equivalent possible children for
// each definition from both the new and old sets of built types.
- if (getTypeSystem() == TypeSystem::Nominal) {
- // No canonicalization to check.
- return;
- }
-
TypeBuilder builder(types.size());
// Helper for creating new definitions of existing types, randomly choosing
@@ -274,36 +269,29 @@ void Fuzzer::checkCanonicalization() {
// Set up recursion groups and record group ends to ensure we only select
// valid children.
recGroupEnds.reserve(builder.size());
- if (getTypeSystem() != TypeSystem::Isorecursive) {
- // No rec groups.
- for (size_t i = 0; i < builder.size(); ++i) {
- recGroupEnds.push_back(builder.size());
+ // Set up recursion groups
+ std::optional<RecGroup> currGroup;
+ size_t currGroupStart = 0;
+ auto finishGroup = [&](Index end) {
+ builder.createRecGroup(currGroupStart, end - currGroupStart);
+ for (Index i = currGroupStart; i < end; ++i) {
+ recGroupEnds.push_back(end);
}
- } else {
- // Set up recursion groups
- std::optional<RecGroup> currGroup;
- size_t currGroupStart = 0;
- auto finishGroup = [&](Index end) {
- builder.createRecGroup(currGroupStart, end - currGroupStart);
- for (Index i = currGroupStart; i < end; ++i) {
- recGroupEnds.push_back(end);
- }
- currGroupStart = end;
- };
- for (Index i = 0; i < types.size(); ++i) {
- auto type = types[i];
- if (type.isBasic()) {
- continue;
- }
- auto newGroup = type.getRecGroup();
- if (!currGroup || newGroup != currGroup ||
- type == types[currGroupStart]) {
- finishGroup(i);
- currGroup = newGroup;
- }
+ currGroupStart = end;
+ };
+ for (Index i = 0; i < types.size(); ++i) {
+ auto type = types[i];
+ if (type.isBasic()) {
+ continue;
+ }
+ auto newGroup = type.getRecGroup();
+ if (!currGroup || newGroup != currGroup ||
+ type == types[currGroupStart]) {
+ finishGroup(i);
+ currGroup = newGroup;
}
- finishGroup(builder.size());
}
+ finishGroup(builder.size());
// Copy the original types
for (; index < types.size(); ++index) {
@@ -349,7 +337,7 @@ void Fuzzer::checkCanonicalization() {
assert(old.isBasic());
return {OldHeapType{old}};
}
- if (!old.isBasic() && getTypeSystem() == TypeSystem::Isorecursive) {
+ if (!old.isBasic()) {
// Check whether this child heap type is supposed to be a self-reference
// into the recursion group we are defining. If it is, we must use the
// corresponding type in the new recursion group, since anything else
@@ -514,7 +502,7 @@ void Fuzzer::checkInhabitable() {
}
// TODO: We could also check that the transformed types are the same as the
// original types up to nullability.
- } else if (getTypeSystem() == TypeSystem::Isorecursive) {
+ } else {
// Verify the produced inhabitable types are the same as the original types
// (which also implies that they are indeed inhabitable).
if (types.size() != inhabitable.size()) {
diff --git a/src/wasm-type.h b/src/wasm-type.h
index d72f5477d..ad0606d59 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -40,17 +40,6 @@
namespace wasm {
-enum class TypeSystem {
- Isorecursive,
- Nominal,
-};
-
-// This should only ever be called before any Types or HeapTypes have been
-// created. The default system is equirecursive.
-void setTypeSystem(TypeSystem system);
-
-TypeSystem getTypeSystem();
-
// Dangerous! Frees all types and heap types that have ever been created and
// resets the type system's internal state. This is only really meant to be used
// for tests.
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index e85740614..967356210 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -229,40 +229,22 @@ void WasmBinaryWriter::writeTypes() {
// the type section. With nominal typing there is always one group and with
// equirecursive typing there is one group per type.
size_t numGroups = 0;
- // MVP types are structural and do not use recursion groups.
- TypeSystem typeSystem = getTypeSystem();
- if (!wasm->features.hasGC()) {
- typeSystem = TypeSystem::Isorecursive;
- }
- switch (typeSystem) {
- case TypeSystem::Nominal:
- numGroups = 1;
- break;
- case TypeSystem::Isorecursive: {
- std::optional<RecGroup> lastGroup;
- for (auto type : indexedTypes.types) {
- auto currGroup = type.getRecGroup();
- numGroups += lastGroup != currGroup;
- lastGroup = currGroup;
- }
+ {
+ std::optional<RecGroup> lastGroup;
+ for (auto type : indexedTypes.types) {
+ auto currGroup = type.getRecGroup();
+ numGroups += lastGroup != currGroup;
+ lastGroup = currGroup;
}
}
BYN_TRACE("== writeTypes\n");
auto start = startSection(BinaryConsts::Section::Type);
o << U32LEB(numGroups);
- if (typeSystem == TypeSystem::Nominal) {
- // The nominal recursion group contains every type.
- o << S32LEB(BinaryConsts::EncodedType::Rec)
- << U32LEB(indexedTypes.types.size());
- }
std::optional<RecGroup> lastGroup = std::nullopt;
for (Index i = 0; i < indexedTypes.types.size(); ++i) {
auto type = indexedTypes.types[i];
// Check whether we need to start a new recursion group. Recursion groups of
- // size 1 are implicit, so only emit a group header for larger groups. This
- // gracefully handles non-isorecursive type systems, which only have groups
- // of size 1 internally (even though nominal types are emitted as a single
- // large group).
+ // size 1 are implicit, so only emit a group header for larger groups.
auto currGroup = type.getRecGroup();
if (lastGroup != currGroup && currGroup.size() > 1) {
o << S32LEB(BinaryConsts::EncodedType::Rec) << U32LEB(currGroup.size());
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 8b1dfb0af..c9c35ac49 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -44,12 +44,6 @@
namespace wasm {
-static TypeSystem typeSystem = TypeSystem::Isorecursive;
-
-void setTypeSystem(TypeSystem system) { typeSystem = system; }
-
-TypeSystem getTypeSystem() { return typeSystem; }
-
namespace {
struct TypeInfo {
@@ -104,11 +98,10 @@ 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;
- // In nominal or isorecursive mode, the supertype of this HeapType, if it
- // exists.
+ // The supertype of this HeapType, if it exists.
HeapTypeInfo* supertype = nullptr;
- // In isorecursive mode, the recursion group of this type or null if the
- // recursion group is trivial (i.e. contains only this type).
+ // The recursion group of this type or null if the recursion group is trivial
+ // (i.e. contains only this type).
RecGroupInfo* recGroup = nullptr;
size_t recGroupIndex = 0;
enum Kind {
@@ -714,12 +707,6 @@ private:
return *canonical;
}
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 (typeSystem == TypeSystem::Nominal) {
- return insertNew();
- }
- }
// Check whether we already have a type for this structural Info.
auto indexIt = typeIDs.find(std::cref(info));
if (indexIt != typeIDs.end()) {
@@ -759,34 +746,6 @@ template<typename Info> bool Store<Info>::isGlobalStore() {
}
#endif
-// Cache canonical nominal signature types. See comment in
-// `HeapType::HeapType(Signature)`.
-struct SignatureTypeCache {
- std::unordered_map<Signature, HeapType> cache;
- std::mutex mutex;
-
- HeapType getType(Signature sig) {
- std::lock_guard<std::mutex> lock(mutex);
- // Try inserting a placeholder type, then replace it with a real type if we
- // don't already have a canonical type for this signature.
- auto [entry, inserted] = cache.insert({sig, {}});
- auto& [_, type] = *entry;
- if (inserted) {
- type = globalHeapTypeStore.insert(sig);
- }
- return type;
- }
-
- void insertType(HeapType type) {
- std::lock_guard<std::mutex> lock(mutex);
- cache.insert({type.getSignature(), type});
- }
-
- void clear() { cache.clear(); }
-};
-
-static SignatureTypeCache nominalSignatureCache;
-
// Keep track of the constructed recursion groups.
struct RecGroupStore {
std::mutex mutex;
@@ -841,7 +800,6 @@ static RecGroupStore globalRecGroupStore;
void destroyAllTypesForTestingPurposesOnly() {
globalTypeStore.clear();
globalHeapTypeStore.clear();
- nominalSignatureCache.clear();
globalRecGroupStore.clear();
}
@@ -1222,24 +1180,8 @@ const Type& Type::Iterator::operator*() const {
HeapType::HeapType(Signature sig) {
assert(!isTemp(sig.params) && "Leaking temporary type!");
assert(!isTemp(sig.results) && "Leaking temporary type!");
- switch (getTypeSystem()) {
- case TypeSystem::Nominal:
- // Special case the creation of signature types in nominal mode to return
- // a "canonical" type for the signature, which happens to be the first one
- // created. We depend on being able to create new function signatures in
- // many places, and historically they have always been structural, so
- // creating a copy of an existing signature did not result in any code
- // bloat or semantic changes. To avoid regressions or significant changes
- // of behavior in nominal mode, we cache the canonical heap types for each
- // signature to emulate structural behavior.
- new (this) HeapType(nominalSignatureCache.getType(sig));
- return;
- case TypeSystem::Isorecursive:
- new (this) HeapType(
- globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(sig)));
- return;
- }
- WASM_UNREACHABLE("unexpected type system");
+ new (this)
+ HeapType(globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(sig)));
}
HeapType::HeapType(const Struct& struct_) {
@@ -1248,16 +1190,8 @@ HeapType::HeapType(const Struct& struct_) {
assert(!isTemp(field.type) && "Leaking temporary type!");
}
#endif
- switch (getTypeSystem()) {
- case TypeSystem::Nominal:
- new (this) HeapType(globalHeapTypeStore.insert(struct_));
- return;
- case TypeSystem::Isorecursive:
- new (this) HeapType(
- globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(struct_)));
- return;
- }
- WASM_UNREACHABLE("unexpected type system");
+ new (this) HeapType(
+ globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(struct_)));
}
HeapType::HeapType(Struct&& struct_) {
@@ -1266,30 +1200,14 @@ HeapType::HeapType(Struct&& struct_) {
assert(!isTemp(field.type) && "Leaking temporary type!");
}
#endif
- switch (getTypeSystem()) {
- case TypeSystem::Nominal:
- new (this) HeapType(globalHeapTypeStore.insert(std::move(struct_)));
- return;
- case TypeSystem::Isorecursive:
- new (this) HeapType(globalRecGroupStore.insert(
- std::make_unique<HeapTypeInfo>(std::move(struct_))));
- return;
- }
- WASM_UNREACHABLE("unexpected type system");
+ new (this) HeapType(globalRecGroupStore.insert(
+ std::make_unique<HeapTypeInfo>(std::move(struct_))));
}
HeapType::HeapType(Array array) {
assert(!isTemp(array.element.type) && "Leaking temporary type!");
- switch (getTypeSystem()) {
- case TypeSystem::Nominal:
- new (this) HeapType(globalHeapTypeStore.insert(array));
- return;
- case TypeSystem::Isorecursive:
- new (this) HeapType(
- globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(array)));
- return;
- }
- WASM_UNREACHABLE("unexpected type system");
+ new (this)
+ HeapType(globalRecGroupStore.insert(std::make_unique<HeapTypeInfo>(array)));
}
bool HeapType::isFunction() const {
@@ -2774,39 +2692,6 @@ validateSubtyping(const std::vector<HeapType>& types) {
return {};
}
-std::optional<TypeBuilder::Error>
-canonicalizeNominal(CanonicalizationState& state) {
- for (auto& info : state.newInfos) {
- info->recGroup = nullptr;
- }
-
- // Nominal types do not require separate canonicalization, so just validate
- // that their subtyping is correct.
-
- // Ensure there are no cycles in the subtype graph. This is the classic DFA
- // algorithm for detecting cycles, but in the form of a simple loop because
- // each node (type) has at most one child (supertype).
- std::unordered_set<HeapTypeInfo*> checked;
- for (size_t i = 0; i < state.results.size(); ++i) {
- HeapType type = state.results[i];
- if (type.isBasic()) {
- continue;
- }
- std::unordered_set<HeapTypeInfo*> path;
- for (auto* curr = getHeapTypeInfo(type);
- curr != nullptr && !checked.count(curr);
- curr = curr->supertype) {
- if (!path.insert(curr).second) {
- return TypeBuilder::Error{i, TypeBuilder::ErrorReason::SelfSupertype};
- }
- }
- // None of the types in `path` reach themselves.
- checked.insert(path.begin(), path.end());
- }
-
- return {};
-}
-
std::optional<TypeBuilder::Error> canonicalizeIsorecursive(
CanonicalizationState& state,
std::vector<std::unique_ptr<RecGroupInfo>>& recGroupInfos) {
@@ -2992,17 +2877,8 @@ TypeBuilder::BuildResult TypeBuilder::build() {
auto start = std::chrono::steady_clock::now();
#endif
- switch (typeSystem) {
- case TypeSystem::Nominal:
- if (auto error = canonicalizeNominal(state)) {
- return {*error};
- }
- break;
- case TypeSystem::Isorecursive:
- if (auto error = canonicalizeIsorecursive(state, impl->recGroups)) {
- return {*error};
- }
- break;
+ if (auto error = canonicalizeIsorecursive(state, impl->recGroups)) {
+ return {*error};
}
#if TIME_CANONICALIZATION
@@ -3026,17 +2902,6 @@ TypeBuilder::BuildResult TypeBuilder::build() {
return {*error};
}
- // Note built signature types. See comment in `HeapType::HeapType(Signature)`.
- for (auto type : state.results) {
- // Do not cache types with explicit supertypes (that is, whose supertype is
- // not HeapType::func). We don't want to reuse such types because then we'd
- // be adding subtyping relationships that are not in the input.
- if (type.isSignature() && (getTypeSystem() == TypeSystem::Nominal) &&
- !type.getSuperType()) {
- nominalSignatureCache.insertType(type);
- }
- }
-
return {state.results};
}
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index 01cc6a9c0..760f4be1d 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -2122,23 +2122,7 @@ void test_func_opt() {
BinaryenModuleDispose(module);
}
-void test_typesystem() {
- BinaryenTypeSystem defaultTypeSystem = BinaryenGetTypeSystem();
- assert(defaultTypeSystem == BinaryenTypeSystemIsorecursive());
- BinaryenSetTypeSystem(BinaryenTypeSystemNominal());
- assert(BinaryenGetTypeSystem() == BinaryenTypeSystemNominal());
- printf("BinaryenTypeSystemNominal: %d\n", BinaryenTypeSystemNominal());
- BinaryenSetTypeSystem(BinaryenTypeSystemIsorecursive());
- assert(BinaryenGetTypeSystem() == BinaryenTypeSystemIsorecursive());
- printf("BinaryenTypeSystemIsorecursive: %d\n",
- BinaryenTypeSystemIsorecursive());
- BinaryenSetTypeSystem(defaultTypeSystem);
-}
-
void test_typebuilder() {
- BinaryenTypeSystem defaultTypeSystem = BinaryenGetTypeSystem();
- BinaryenSetTypeSystem(BinaryenTypeSystemIsorecursive());
-
printf("TypeBuilderErrorReasonSelfSupertype: %d\n",
TypeBuilderErrorReasonSelfSupertype());
printf("TypeBuilderErrorReasonInvalidSupertype: %d\n",
@@ -2344,8 +2328,6 @@ void test_typebuilder() {
printf("module with recursive GC types:\n");
BinaryenModulePrint(module);
BinaryenModuleDispose(module);
-
- BinaryenSetTypeSystem(defaultTypeSystem);
}
int main() {
@@ -2360,7 +2342,6 @@ int main() {
test_color_status();
test_for_each();
test_func_opt();
- test_typesystem();
test_typebuilder();
return 0;
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index dcfd6de8c..1c1a3b956 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -3147,8 +3147,6 @@ optimized:
(i32.const 4)
)
)
-BinaryenTypeSystemNominal: 1
-BinaryenTypeSystemIsorecursive: 0
TypeBuilderErrorReasonSelfSupertype: 0
TypeBuilderErrorReasonInvalidSupertype: 1
TypeBuilderErrorReasonForwardSupertypeReference: 2
diff --git a/test/example/type-builder-nominal.cpp b/test/example/type-builder-nominal.cpp
deleted file mode 100644
index a3e8695ac..000000000
--- a/test/example/type-builder-nominal.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-#include <cassert>
-#include <iostream>
-
-#include "wasm-builder.h"
-#include "wasm-type-printing.h"
-#include "wasm-type.h"
-
-using namespace wasm;
-
-// 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))))
- // (type $array (array (mut anyref)))
-
- TypeBuilder builder;
- assert(builder.size() == 0);
- builder.grow(3);
- assert(builder.size() == 3);
-
- 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 refNullAny(HeapType::any, Nullable);
-
- Signature sig(refStruct, builder.getTempTupleType({refArray, Type::i32}));
- Struct struct_({Field(refNullArray, Immutable)});
- Array array(Field(refNullAny, Mutable));
-
- {
- IndexedTypeNameGenerator print(builder);
- std::cout << "Before setting heap types:\n";
- std::cout << "$sig => " << print(builder[0]) << "\n";
- std::cout << "$struct => " << print(builder[1]) << "\n";
- std::cout << "$array => " << print(builder[2]) << "\n";
- std::cout << "(ref $sig) => " << print(refSig) << "\n";
- std::cout << "(ref $struct) => " << print(refStruct) << "\n";
- std::cout << "(ref $array) => " << print(refArray) << "\n";
- std::cout << "(ref null $array) => " << print(refNullArray) << "\n";
- }
-
- builder[0] = sig;
- builder[1] = struct_;
- builder[2] = array;
-
- {
- IndexedTypeNameGenerator print(builder);
- std::cout << "After setting heap types:\n";
- std::cout << "$sig => " << print(builder[0]) << "\n";
- std::cout << "$struct => " << print(builder[1]) << "\n";
- std::cout << "$array => " << print(builder[2]) << "\n";
- std::cout << "(ref $sig) => " << print(refSig) << "\n";
- std::cout << "(ref $struct) => " << print(refStruct) << "\n";
- std::cout << "(ref $array) => " << print(refArray) << "\n";
- std::cout << "(ref null $array) => " << print(refNullArray) << "\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);
-
- {
- IndexedTypeNameGenerator print(built);
- std::cout << "After building types:\n";
- std::cout << "$sig => " << print(built[0]) << "\n";
- std::cout << "$struct => " << print(built[1]) << "\n";
- std::cout << "$array => " << print(built[2]) << "\n";
- std::cout << "(ref $sig) => " << print(newRefSig) << "\n";
- std::cout << "(ref $struct) => " << print(newRefStruct) << "\n";
- std::cout << "(ref $array) => " << print(newRefArray) << "\n";
- std::cout << "(ref null $array) => " << print(newRefNullArray) << "\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);
-
- 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";
-
- Type canonAnyref = Type(HeapType::any, Nullable);
- Type canonI31ref = Type(HeapType::i31, NonNullable);
-
- TypeBuilder builder(6);
-
- Type anyref = builder.getTempRefType(builder[4], Nullable);
- Type i31ref = builder.getTempRefType(builder[5], NonNullable);
-
- builder[0] = Signature(canonAnyref, canonI31ref);
- builder[1] = Signature(anyref, canonI31ref);
- builder[2] = Signature(canonAnyref, 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(canonAnyref, canonI31ref));
- 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);
-}
-
-// Check that signatures created with TypeBuilders are properly recorded as
-// canonical.
-void test_signatures(bool warm) {
- std::cout << ";; Test canonical signatures\n";
-
- Type canonAnyref = Type(HeapType::any, Nullable);
- Type canonI31ref = Type(HeapType::i31, NonNullable);
-
- TypeBuilder builder(2);
- Type tempRef = builder.getTempRefType(builder[0], Nullable);
- builder[0] = Signature(canonI31ref, canonAnyref);
- builder[1] = Signature(tempRef, tempRef);
- std::vector<HeapType> built = *builder.build();
-
- HeapType small = Signature(canonI31ref, canonAnyref);
- HeapType big = Signature(Type(Signature(canonI31ref, canonAnyref), Nullable),
- Type(Signature(canonI31ref, canonAnyref), Nullable));
- if (warm) {
- assert(built[0] != small);
- assert(built[1] != big);
- } else {
- assert(built[0] == small);
- assert(built[1] == big);
- }
-}
-
-void test_recursive() {
- std::cout << ";; Test recursive types\n";
-
- {
- // Trivial recursion
- std::vector<HeapType> built;
- {
- TypeBuilder builder(1);
- Type temp = builder.getTempRefType(builder[0], Nullable);
- builder[0] = Signature(Type::none, temp);
- built = *builder.build();
- }
- IndexedTypeNameGenerator print(built);
- std::cout << print(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);
- 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();
- }
- IndexedTypeNameGenerator print(built);
- std::cout << print(built[0]) << "\n";
- std::cout << print(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);
- 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();
- }
- IndexedTypeNameGenerator print(built);
- std::cout << print(built[0]) << "\n";
- std::cout << print(built[1]) << "\n";
- std::cout << print(built[2]) << "\n";
- std::cout << print(built[3]) << "\n";
- std::cout << print(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);
- 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();
- }
- IndexedTypeNameGenerator print(built);
- std::cout << print(built[0]) << "\n";
- std::cout << print(built[1]) << "\n";
- std::cout << print(built[2]) << "\n";
- std::cout << print(built[3]) << "\n";
- std::cout << print(built[4]) << "\n";
- std::cout << print(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);
- Type temp0 = builder.getTempRefType(builder[0], Nullable);
- builder[0] = Signature(Type::none, temp0);
- builder[1] = Signature(Type::none, temp0);
- built = *builder.build();
- }
- IndexedTypeNameGenerator print(built);
- std::cout << print(built[0]) << "\n";
- std::cout << print(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";
-
- Type anyref = Type(HeapType::any, Nullable);
- Type eqref = Type(HeapType::eq, Nullable);
-
- 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;
- };
-
- {
- // Subtype declarations, but still no subtypes
- std::vector<HeapType> built;
- {
- TypeBuilder builder(3);
- builder[0].subTypeOf(builder[1]);
- builder[0] = Struct{};
- builder[1] = Struct{};
- builder[2] = Struct{};
- built = *builder.build();
- }
- assert(LUB(built[0], built[2]) == HeapType::struct_);
- }
-
- {
- // Subtyping of identical types
- std::vector<HeapType> built;
- {
- TypeBuilder builder(6);
- builder[0].subTypeOf(builder[1]);
- builder[2].subTypeOf(builder[3]);
- builder[4].subTypeOf(builder[5]);
- builder[0] = Struct({Field(Type::i32, Mutable), Field(anyref, Mutable)});
- builder[1] = Struct({Field(Type::i32, Mutable), Field(anyref, Mutable)});
- builder[2] = Signature(Type::i32, anyref);
- builder[3] = Signature(Type::i32, 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);
- 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);
- builder[0] = Struct({Field(anyref, Immutable)});
- builder[1] = Struct({Field(eqref, 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);
- 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() {
- wasm::setTypeSystem(TypeSystem::Nominal);
-
- // 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_signatures(i == 1);
- test_recursive();
- test_subtypes();
- }
-}
diff --git a/test/example/type-builder-nominal.txt b/test/example/type-builder-nominal.txt
deleted file mode 100644
index 4da8857f2..000000000
--- a/test/example/type-builder-nominal.txt
+++ /dev/null
@@ -1,102 +0,0 @@
-;; Test TypeBuilder
-Before setting heap types:
-$sig => (type $0 (; temp ;) (func))
-$struct => (type $1 (; temp ;) (func))
-$array => (type $2 (; temp ;) (func))
-(ref $sig) => (; temp ;) (ref $0)
-(ref $struct) => (; temp ;) (ref $1)
-(ref $array) => (; temp ;) (ref $2)
-(ref null $array) => (; temp ;) (ref null $2)
-After setting heap types:
-$sig => (type $0 (; temp ;) (func (param (; temp ;) (ref $1)) (result (; temp ;) (ref $2) i32)))
-$struct => (type $1 (; temp ;) (struct (field (; temp ;) (ref null $2))))
-$array => (type $2 (; temp ;) (array (mut anyref)))
-(ref $sig) => (; temp ;) (ref $0)
-(ref $struct) => (; temp ;) (ref $1)
-(ref $array) => (; temp ;) (ref $2)
-(ref null $array) => (; temp ;) (ref null $2)
-After building types:
-$sig => (type $0 (func (param (ref $1)) (result (ref $2) i32)))
-$struct => (type $1 (struct (field (ref null $2))))
-$array => (type $2 (array (mut anyref)))
-(ref $sig) => (ref $0)
-(ref $struct) => (ref $1)
-(ref $array) => (ref $2)
-(ref null $array) => (ref null $2)
-;; Test canonicalization
-;; Test basic
-;; Test canonical signatures
-;; Test recursive types
-(type $0 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $1))))
-(type $1 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $1))))
-(type $1 (func (result (ref null $2))))
-(type $2 (func (result (ref null $3))))
-(type $3 (func (result (ref null $4))))
-(type $4 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $0) (ref null $2))))
-(type $1 (func (result (ref null $1) (ref null $3))))
-(type $2 (func))
-(type $3 (func))
-(type $4 (func (result (ref null $0))))
-(type $5 (func (result (ref null $1))))
-
-(type $0 (func (result (ref null $0))))
-(type $1 (func (result (ref null $0))))
-
-;; Test subtyping
-;; Test TypeBuilder
-Before setting heap types:
-$sig => (type $0 (; temp ;) (func))
-$struct => (type $1 (; temp ;) (func))
-$array => (type $2 (; temp ;) (func))
-(ref $sig) => (; temp ;) (ref $0)
-(ref $struct) => (; temp ;) (ref $1)
-(ref $array) => (; temp ;) (ref $2)
-(ref null $array) => (; temp ;) (ref null $2)
-After setting heap types:
-$sig => (type $0 (; temp ;) (func (param (; temp ;) (ref $1)) (result (; temp ;) (ref $2) i32)))
-$struct => (type $1 (; temp ;) (struct (field (; temp ;) (ref null $2))))
-$array => (type $2 (; temp ;) (array (mut anyref)))
-(ref $sig) => (; temp ;) (ref $0)
-(ref $struct) => (; temp ;) (ref $1)
-(ref $array) => (; temp ;) (ref $2)
-(ref null $array) => (; temp ;) (ref null $2)
-After building types:
-$sig => (type $0 (func (param (ref $1)) (result (ref $2) i32)))
-$struct => (type $1 (struct (field (ref null $2))))
-$array => (type $2 (array (mut anyref)))
-(ref $sig) => (ref $0)
-(ref $struct) => (ref $1)
-(ref $array) => (ref $2)
-(ref null $array) => (ref null $2)
-;; Test canonicalization
-;; Test basic
-;; Test canonical signatures
-;; Test recursive types
-(type $0 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $1))))
-(type $1 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $1))))
-(type $1 (func (result (ref null $2))))
-(type $2 (func (result (ref null $3))))
-(type $3 (func (result (ref null $4))))
-(type $4 (func (result (ref null $0))))
-
-(type $0 (func (result (ref null $0) (ref null $2))))
-(type $1 (func (result (ref null $1) (ref null $3))))
-(type $2 (func))
-(type $3 (func))
-(type $4 (func (result (ref null $0))))
-(type $5 (func (result (ref null $1))))
-
-(type $0 (func (result (ref null $0))))
-(type $1 (func (result (ref null $0))))
-
-;; Test subtyping
diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp
index dc10c00bf..85a4e86fd 100644
--- a/test/gtest/possible-contents.cpp
+++ b/test/gtest/possible-contents.cpp
@@ -66,11 +66,6 @@ static std::unique_ptr<Module> parse(std::string module) {
// that.
class PossibleContentsTest : public testing::Test {
protected:
- void SetUp() override {
- // Use nominal typing to test struct types.
- wasm::setTypeSystem(TypeSystem::Nominal);
- }
-
Type anyref = Type(HeapType::any, Nullable);
Type funcref = Type(HeapType::func, Nullable);
Type i31ref = Type(HeapType::i31, Nullable);
@@ -542,6 +537,7 @@ TEST_F(PossibleContentsTest, TestStructCones) {
D
*/
TypeBuilder builder(5);
+ builder.createRecGroup(0, 5);
builder.setHeapType(0, Struct(FieldList{}));
builder.setHeapType(1, Struct(FieldList{}));
builder.setHeapType(2, Struct(FieldList{}));
diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp
index af6613bd2..7d5f5aa98 100644
--- a/test/gtest/type-builder.cpp
+++ b/test/gtest/type-builder.cpp
@@ -156,7 +156,7 @@ TEST_F(TypeTest, ModuleTypePrinter) {
EXPECT_EQ(stream.str(), "(type $1 (struct (field i32)))");
}
-TEST_F(IsorecursiveTest, Basics) {
+TEST_F(TypeTest, Basics) {
// (type $sig (func (param (ref $struct)) (result (ref $array) i32)))
// (type $struct (struct (field (ref null $array))))
// (type $array (array (mut anyref)))
@@ -207,7 +207,7 @@ TEST_F(IsorecursiveTest, Basics) {
EXPECT_NE(newRefNullArray, refNullArray);
}
-static void testDirectSelfSupertype() {
+TEST_F(TypeTest, DirectSelfSupertype) {
// Type is directly a supertype of itself.
TypeBuilder builder(1);
builder[0] = Struct{};
@@ -218,19 +218,11 @@ static void testDirectSelfSupertype() {
const auto* error = result.getError();
ASSERT_TRUE(error);
- if (getTypeSystem() == TypeSystem::Nominal) {
- EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
- } else if (getTypeSystem() == TypeSystem::Isorecursive) {
- EXPECT_EQ(error->reason,
- TypeBuilder::ErrorReason::ForwardSupertypeReference);
- }
+ EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::ForwardSupertypeReference);
EXPECT_EQ(error->index, 0u);
}
-TEST_F(NominalTest, DirectSelfSupertype) { testDirectSelfSupertype(); }
-TEST_F(IsorecursiveTest, DirectSelfSupertype) { testDirectSelfSupertype(); }
-
-static void testIndirectSelfSupertype() {
+TEST_F(TypeTest, IndirectSelfSupertype) {
// Type is indirectly a supertype of itself.
TypeBuilder builder(2);
builder.createRecGroup(0, 2);
@@ -244,21 +236,11 @@ static void testIndirectSelfSupertype() {
const auto* error = result.getError();
ASSERT_TRUE(error);
- if (getTypeSystem() == TypeSystem::Nominal) {
- EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
- } else if (getTypeSystem() == TypeSystem::Isorecursive) {
- EXPECT_EQ(error->reason,
- TypeBuilder::ErrorReason::ForwardSupertypeReference);
- } else {
- WASM_UNREACHABLE("unexpected type system");
- }
+ EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::ForwardSupertypeReference);
EXPECT_EQ(error->index, 0u);
}
-TEST_F(NominalTest, IndirectSelfSupertype) { testIndirectSelfSupertype(); }
-TEST_F(IsorecursiveTest, IndirectSelfSupertype) { testIndirectSelfSupertype(); }
-
-static void testInvalidSupertype() {
+TEST_F(TypeTest, InvalidSupertype) {
TypeBuilder builder(2);
builder.createRecGroup(0, 2);
builder[0] = Struct({Field(Type::i32, Immutable)});
@@ -274,10 +256,7 @@ static void testInvalidSupertype() {
EXPECT_EQ(error->index, 1u);
}
-TEST_F(NominalTest, InvalidSupertype) { testInvalidSupertype(); }
-TEST_F(IsorecursiveTest, InvalidSupertype) { testInvalidSupertype(); }
-
-TEST_F(IsorecursiveTest, ForwardReferencedChild) {
+TEST_F(TypeTest, ForwardReferencedChild) {
TypeBuilder builder(3);
builder.createRecGroup(0, 2);
Type refA1 = builder.getTempRefType(builder[1], Nullable);
@@ -297,7 +276,7 @@ TEST_F(IsorecursiveTest, ForwardReferencedChild) {
EXPECT_EQ(error->index, 1u);
}
-TEST_F(IsorecursiveTest, RecGroupIndices) {
+TEST_F(TypeTest, RecGroupIndices) {
TypeBuilder builder(5);
builder.createRecGroup(0, 2);
@@ -324,7 +303,7 @@ TEST_F(IsorecursiveTest, RecGroupIndices) {
EXPECT_EQ(built[4].getRecGroupIndex(), 2u);
}
-TEST_F(IsorecursiveTest, CanonicalizeGroups) {
+TEST_F(TypeTest, CanonicalizeGroups) {
// Trivial types in the same group are not equivalent.
TypeBuilder builderA(2);
builderA.createRecGroup(0, 2);
@@ -374,7 +353,7 @@ TEST_F(IsorecursiveTest, CanonicalizeGroups) {
EXPECT_EQ(builtB2[0], builtB[0]);
}
-TEST_F(IsorecursiveTest, CanonicalizeUses) {
+TEST_F(TypeTest, CanonicalizeUses) {
TypeBuilder builder(8);
builder[0] = makeStruct(builder, {});
builder[1] = makeStruct(builder, {});
@@ -402,7 +381,7 @@ TEST_F(IsorecursiveTest, CanonicalizeUses) {
EXPECT_NE(built[4], built[6]);
}
-TEST_F(IsorecursiveTest, CanonicalizeSelfReferences) {
+TEST_F(TypeTest, CanonicalizeSelfReferences) {
TypeBuilder builder(5);
// Single self-reference
builder[0] = makeStruct(builder, {0});
@@ -428,7 +407,7 @@ TEST_F(IsorecursiveTest, CanonicalizeSelfReferences) {
EXPECT_NE(built[3], built[4]);
}
-TEST_F(IsorecursiveTest, CanonicalizeSupertypes) {
+TEST_F(TypeTest, CanonicalizeSupertypes) {
TypeBuilder builder(6);
builder[0] = Struct{};
builder[1] = Struct{};
@@ -455,7 +434,7 @@ TEST_F(IsorecursiveTest, CanonicalizeSupertypes) {
EXPECT_NE(built[4], built[5]);
}
-TEST_F(IsorecursiveTest, HeapTypeConstructors) {
+TEST_F(TypeTest, HeapTypeConstructors) {
HeapType sig(Signature(Type::i32, Type::i32));
HeapType struct_(Struct({Field(Type(sig, Nullable), Mutable)}));
HeapType array(Field(Type(struct_, Nullable), Mutable));
@@ -484,7 +463,7 @@ TEST_F(IsorecursiveTest, HeapTypeConstructors) {
EXPECT_EQ(array, array2);
}
-TEST_F(IsorecursiveTest, CanonicalizeTypesBeforeSubtyping) {
+TEST_F(TypeTest, CanonicalizeTypesBeforeSubtyping) {
TypeBuilder builder(6);
// A rec group
builder.createRecGroup(0, 2);
@@ -510,7 +489,7 @@ TEST_F(IsorecursiveTest, CanonicalizeTypesBeforeSubtyping) {
EXPECT_TRUE(result);
}
-TEST_F(IsorecursiveTest, CanonicalizeBasicTypes) {
+TEST_F(TypeTest, CanonicalizeBasicTypes) {
TypeBuilder builder(5);
Type anyref = builder.getTempRefType(builder[0], Nullable);
@@ -532,7 +511,7 @@ TEST_F(IsorecursiveTest, CanonicalizeBasicTypes) {
EXPECT_EQ(built[3], built[4]);
}
-TEST_F(IsorecursiveTest, TestHeapTypeRelations) {
+TEST_F(TypeTest, TestHeapTypeRelations) {
HeapType ext = HeapType::ext;
HeapType func = HeapType::func;
HeapType any = HeapType::any;
@@ -829,7 +808,7 @@ TEST_F(IsorecursiveTest, TestHeapTypeRelations) {
}
}
-TEST_F(IsorecursiveTest, TestSubtypeErrors) {
+TEST_F(TypeTest, TestSubtypeErrors) {
Type anyref = Type(HeapType::any, Nullable);
Type eqref = Type(HeapType::eq, Nullable);
Type funcref = Type(HeapType::func, Nullable);
@@ -872,7 +851,7 @@ TEST_F(IsorecursiveTest, TestSubtypeErrors) {
}
// Test SubTypes utility code.
-TEST_F(NominalTest, TestSubTypes) {
+TEST_F(TypeTest, TestSubTypes) {
Type anyref = Type(HeapType::any, Nullable);
Type eqref = Type(HeapType::eq, Nullable);
@@ -907,40 +886,7 @@ TEST_F(NominalTest, TestSubTypes) {
}
// Test reuse of a previously built type as supertype.
-TEST_F(NominalTest, TestExistingSuperType) {
- // Build an initial type A
- Type A;
- {
- TypeBuilder builder(1);
- builder[0] = Struct();
- auto result = builder.build();
- ASSERT_TRUE(result);
- auto built = *result;
- A = Type(built[0], Nullable);
- }
-
- // Build a type B <: A using a new builder
- Type B;
- {
- TypeBuilder builder(1);
- builder[0] = Struct();
- builder.setSubType(0, A.getHeapType());
- auto result = builder.build();
- ASSERT_TRUE(result);
- auto built = *result;
- B = Type(built[0], Nullable);
- }
-
- // Test that B <: A where A is the initial type A
- auto superOfB = B.getHeapType().getSuperType();
- ASSERT_TRUE(superOfB);
- EXPECT_EQ(*superOfB, A.getHeapType());
- EXPECT_NE(B.getHeapType(), A.getHeapType());
-}
-
-// Test reuse of a previously built type as supertype, where in isorecursive
-// mode canonicalization is performed.
-TEST_F(IsorecursiveTest, TestExistingSuperType) {
+TEST_F(TypeTest, TestExistingSuperType) {
// Build an initial type A1
Type A1;
{
@@ -993,7 +939,7 @@ TEST_F(IsorecursiveTest, TestExistingSuperType) {
}
// Test .getMaxDepths() helper.
-TEST_F(NominalTest, TestMaxStructDepths) {
+TEST_F(TypeTest, TestMaxStructDepths) {
/*
A
|
@@ -1022,7 +968,7 @@ TEST_F(NominalTest, TestMaxStructDepths) {
EXPECT_EQ(maxDepths[HeapType::any], Index(4));
}
-TEST_F(NominalTest, TestMaxArrayDepths) {
+TEST_F(TypeTest, TestMaxArrayDepths) {
HeapType A;
{
TypeBuilder builder(1);
@@ -1043,7 +989,7 @@ TEST_F(NominalTest, TestMaxArrayDepths) {
}
// Test .depth() helper.
-TEST_F(NominalTest, TestDepth) {
+TEST_F(TypeTest, TestDepth) {
HeapType A, B, C;
{
TypeBuilder builder(3);
@@ -1086,7 +1032,7 @@ TEST_F(NominalTest, TestDepth) {
}
// Test .iterSubTypes() helper.
-TEST_F(NominalTest, TestIterSubTypes) {
+TEST_F(TypeTest, TestIterSubTypes) {
/*
A
/ \
diff --git a/test/gtest/type-test.h b/test/gtest/type-test.h
index 49c6381fa..f029b8027 100644
--- a/test/gtest/type-test.h
+++ b/test/gtest/type-test.h
@@ -5,19 +5,10 @@
#define wasm_test_gtest_type_test_h
// Helper test fixture for managing the global type system state.
-template<wasm::TypeSystem system>
-class TypeSystemTest : public ::testing::Test {
- wasm::TypeSystem originalSystem;
+class TypeTest : public ::testing::Test {
protected:
- void SetUp() override {
- originalSystem = wasm::getTypeSystem();
- wasm::setTypeSystem(system);
- }
- void TearDown() override {
- wasm::destroyAllTypesForTestingPurposesOnly();
- wasm::setTypeSystem(originalSystem);
- }
+ void TearDown() override { wasm::destroyAllTypesForTestingPurposesOnly(); }
// Utilities
wasm::Struct makeStruct(wasm::TypeBuilder& builder,
@@ -32,8 +23,4 @@ protected:
}
};
-using TypeTest = TypeSystemTest<wasm::TypeSystem::Isorecursive>;
-using NominalTest = TypeSystemTest<wasm::TypeSystem::Nominal>;
-using IsorecursiveTest = TypeSystemTest<wasm::TypeSystem::Isorecursive>;
-
#endif // wasm_test_gtest_type_test_h