summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/support/index.h29
-rw-r--r--src/tools/wasm-fuzz-types.cpp23
-rw-r--r--src/wasm-type-printing.h88
-rw-r--r--src/wasm-type.h55
-rw-r--r--src/wasm.h9
-rw-r--r--src/wasm/wasm-type.cpp229
-rw-r--r--test/example/type-builder-nominal.cpp81
-rw-r--r--test/example/type-builder-nominal.txt150
-rw-r--r--test/example/type-builder.cpp43
-rw-r--r--test/example/type-builder.txt64
-rw-r--r--test/example/typeinfo.cpp1
-rw-r--r--test/example/typeinfo.txt94
-rw-r--r--test/lit/fuzz-types/isorecursive.test40
-rw-r--r--test/lit/fuzz-types/nominal.test43
-rw-r--r--test/lit/fuzz-types/structural.test41
15 files changed, 630 insertions, 360 deletions
diff --git a/src/support/index.h b/src/support/index.h
new file mode 100644
index 000000000..c4177286a
--- /dev/null
+++ b/src/support/index.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2022 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_support_index_h
+#define wasm_support_index_h
+
+#include <cstdint>
+
+namespace wasm {
+
+// An index in a wasm module
+using Index = uint32_t;
+
+} // namespace wasm
+
+#endif // wasm_support_index_h
diff --git a/src/tools/wasm-fuzz-types.cpp b/src/tools/wasm-fuzz-types.cpp
index 983d949d0..4b1f2800e 100644
--- a/src/tools/wasm-fuzz-types.cpp
+++ b/src/tools/wasm-fuzz-types.cpp
@@ -21,6 +21,7 @@
#include "support/command-line.h"
#include "tools/fuzzing/heap-types.h"
#include "tools/fuzzing/random.h"
+#include "wasm-type-printing.h"
namespace wasm {
@@ -79,8 +80,28 @@ void Fuzzer::run(uint64_t seed) {
void Fuzzer::printTypes(const std::vector<HeapType>& types) {
std::cout << "Built " << types.size() << " types:\n";
+ struct FatalTypeNameGenerator
+ : TypeNameGeneratorBase<FatalTypeNameGenerator> {
+ TypeNames getNames(HeapType type) {
+ Fatal() << "trying to print unknown heap type";
+ }
+ };
+ IndexedTypeNameGenerator<FatalTypeNameGenerator> print(types);
+ std::unordered_map<HeapType, size_t> seen;
for (size_t i = 0; i < types.size(); ++i) {
- std::cout << i << ": " << types[i] << "\n";
+ auto type = types[i];
+ std::cout << "(type $" << i << ' ';
+ if (type.isBasic()) {
+ std::cout << print(type) << ")\n";
+ continue;
+ }
+ auto [it, inserted] = seen.insert({type, i});
+ if (inserted) {
+ std::cout << print(type);
+ } else {
+ std::cout << "identical to $" << it->second;
+ }
+ std::cout << ")\n";
}
}
diff --git a/src/wasm-type-printing.h b/src/wasm-type-printing.h
new file mode 100644
index 000000000..fcf05db17
--- /dev/null
+++ b/src/wasm-type-printing.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2022 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_wasm_type_printing_h
+#define wasm_wasm_type_printing_h
+
+#include <cstddef>
+#include <iostream>
+#include <unordered_map>
+
+#include "support/name.h"
+#include "support/utilities.h"
+#include "wasm-type.h"
+
+namespace wasm {
+
+// CRTP base that all other type name generators should subclass. Provides the
+// ability to use the generator as a function to print Types and HeapTypes to
+// streams.
+template<typename Subclass> struct TypeNameGeneratorBase {
+ TypeNames getNames(HeapType type) {
+ static_assert(&TypeNameGeneratorBase<Subclass>::getNames !=
+ &Subclass::getNames,
+ "Derived class must implement getNames");
+ WASM_UNREACHABLE("Derived class must implement getNames");
+ }
+ HeapType::Printed operator()(HeapType type) {
+ return type.print(
+ [&](HeapType ht) { return static_cast<Subclass*>(this)->getNames(ht); });
+ }
+ Type::Printed operator()(Type type) {
+ return type.print(
+ [&](HeapType ht) { return static_cast<Subclass*>(this)->getNames(ht); });
+ }
+};
+
+// Generates names like "func.0", "struct.1", "array.2", etc. Struct fields are
+// not given names.
+struct DefaultTypeNameGenerator
+ : TypeNameGeneratorBase<DefaultTypeNameGenerator> {
+ size_t funcCount = 0;
+ size_t structCount = 0;
+ size_t arrayCount = 0;
+
+ // Cached names for types that have already been seen.
+ std::unordered_map<HeapType, TypeNames> nameCache;
+
+ TypeNames getNames(HeapType type);
+};
+
+// Generates names based on the indices of types in some collection, falling
+// back to the given FallbackGenerator when encountering a type not in the
+// collection. Struct fields are not given names.
+template<typename FallbackGenerator = DefaultTypeNameGenerator>
+struct IndexedTypeNameGenerator
+ : TypeNameGeneratorBase<IndexedTypeNameGenerator<FallbackGenerator>> {
+ FallbackGenerator fallback;
+ std::unordered_map<HeapType, TypeNames> names;
+ template<typename T> IndexedTypeNameGenerator(T& types) {
+ for (size_t i = 0; i < types.size(); ++i) {
+ names.insert({types[i], {std::to_string(i), {}}});
+ }
+ }
+ TypeNames getNames(HeapType type) {
+ if (auto it = names.find(type); it != names.end()) {
+ return it->second;
+ } else {
+ return fallback.getNames(type);
+ }
+ }
+};
+
+} // namespace wasm
+
+#endif // wasm_wasm_type_printing_h
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 8c8d85ebf..29e5114b7 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -17,14 +17,18 @@
#ifndef wasm_wasm_type_h
#define wasm_wasm_type_h
-#include "support/name.h"
-#include "support/parent_index_iterator.h"
-#include "wasm-features.h"
+#include <functional>
#include <optional>
#include <ostream>
+#include <string>
#include <variant>
#include <vector>
+#include "support/index.h"
+#include "support/name.h"
+#include "support/parent_index_iterator.h"
+#include "wasm-features.h"
+
// TODO: At various code locations we were assuming that single types are basic
// types, but this is going to change with the introduction of the compound
// Signature, Struct and Array types that will be single but not basic. To
@@ -68,6 +72,17 @@ struct Rtt;
enum Nullability { NonNullable, Nullable };
enum Mutability { Immutable, Mutable };
+// HeapType name information used for printing.
+struct TypeNames {
+ // The name of the type.
+ Name name;
+ // For a Struct, names of fields.
+ std::unordered_map<Index, Name> fieldNames;
+};
+
+// Used to generate HeapType names.
+using HeapTypeNameGenerator = std::function<TypeNames(HeapType)>;
+
// The type used for interning IDs in the public interfaces of Type and
// HeapType.
using TypeID = uint64_t;
@@ -271,6 +286,22 @@ public:
return lub;
}
+ // Helper allowing the value of `print(...)` to be sent to an ostream. Stores
+ // a `TypeID` because `Type` is incomplete at this point and using a reference
+ // makes it less convenient to use.
+ struct Printed {
+ TypeID typeID;
+ HeapTypeNameGenerator generateName;
+ };
+
+ // Given a function for generating non-basic HeapType names, print this Type
+ // to `os`.`generateName` should return the same name each time it is called
+ // with the same HeapType and it should return different names for different
+ // types.
+ Printed print(HeapTypeNameGenerator generateName) {
+ return Printed{getID(), generateName};
+ }
+
std::string toString() const;
size_t size() const;
@@ -385,6 +416,22 @@ public:
// Return the LUB of two HeapTypes. The LUB always exists.
static HeapType getLeastUpperBound(HeapType a, HeapType b);
+ // Helper allowing the value of `print(...)` to be sent to an ostream. Stores
+ // a `TypeID` because `Type` is incomplete at this point and using a reference
+ // makes it less convenient to use.
+ struct Printed {
+ TypeID typeID;
+ HeapTypeNameGenerator generateName;
+ };
+
+ // Given a function for generating HeapType names, print the definition of
+ // this HeapType to `os`. `generateName` should return the same
+ // name each time it is called with the same HeapType and it should return
+ // different names for different types.
+ Printed print(HeapTypeNameGenerator generateName) {
+ return Printed{getID(), generateName};
+ }
+
std::string toString() const;
};
@@ -667,7 +714,9 @@ struct TypeBuilder {
};
std::ostream& operator<<(std::ostream&, Type);
+std::ostream& operator<<(std::ostream&, Type::Printed);
std::ostream& operator<<(std::ostream&, HeapType);
+std::ostream& operator<<(std::ostream&, HeapType::Printed);
std::ostream& operator<<(std::ostream&, Tuple);
std::ostream& operator<<(std::ostream&, Signature);
std::ostream& operator<<(std::ostream&, Field);
diff --git a/src/wasm.h b/src/wasm.h
index 18662ad8e..153cb4764 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -34,6 +34,7 @@
#include "literal.h"
#include "mixed_arena.h"
+#include "support/index.h"
#include "support/name.h"
#include "wasm-features.h"
#include "wasm-type.h"
@@ -1971,14 +1972,6 @@ public:
// Module name, if specified. Serves a documentary role only.
Name name;
- // Optional type name information, used in printing only. Note that Types are
- // globally interned, but type names are specific to a module.
- struct TypeNames {
- // The name of the type.
- Name name;
- // For a Struct, names of fields.
- std::unordered_map<Index, Name> fieldNames;
- };
std::unordered_map<HeapType, TypeNames> typeNames;
MixedArena allocator;
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 27480ce68..04b1122b6 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -28,6 +28,7 @@
#include "support/hash.h"
#include "support/insert_ordered.h"
#include "wasm-features.h"
+#include "wasm-type-printing.h"
#include "wasm-type.h"
#define TRACE_CANONICALIZATION 0
@@ -196,42 +197,43 @@ private:
std::optional<Rtt> lub(const Rtt& a, const Rtt& b);
};
-// Helper for printing types without infinitely recursing on recursive types.
+// Helper for printing types.
struct TypePrinter {
- size_t currDepth = 0;
- std::unordered_map<TypeID, size_t> depths;
+ // Whether to print explicit supertypes.
+ bool printSupertypes;
// The stream we are printing to.
std::ostream& os;
- TypePrinter(std::ostream& os) : os(os) {}
+ // The default generator state if no other generator is provided.
+ std::optional<DefaultTypeNameGenerator> defaultGenerator;
+
+ // The function we call to get HeapType names.
+ HeapTypeNameGenerator generator;
+
+ TypePrinter(std::ostream& os, HeapTypeNameGenerator generator)
+ : printSupertypes(getTypeSystem() != TypeSystem::Equirecursive), os(os),
+ defaultGenerator(), generator(generator) {}
+ TypePrinter(std::ostream& os)
+ : TypePrinter(
+ os, [&](HeapType type) { return defaultGenerator->getNames(type); }) {
+ defaultGenerator = DefaultTypeNameGenerator{};
+ }
+
+ void printHeapTypeName(HeapType type);
+ void printSupertypeOr(std::optional<HeapType> super, std::string other);
std::ostream& print(Type type);
- std::ostream& print(HeapType heapType);
+ std::ostream& print(HeapType type);
std::ostream& print(const Tuple& tuple);
std::ostream& print(const Field& field);
- std::ostream& print(const Signature& sig);
- std::ostream& print(const Struct& struct_);
- std::ostream& print(const Array& array);
+ std::ostream& print(const Signature& sig,
+ std::optional<HeapType> super = std::nullopt);
+ std::ostream& print(const Struct& struct_,
+ std::optional<HeapType> super = std::nullopt);
+ std::ostream& print(const Array& array,
+ std::optional<HeapType> super = std::nullopt);
std::ostream& print(const Rtt& rtt);
-
-private:
- template<typename T, typename F> std::ostream& printChild(T curr, F printer);
-
- // FIXME: This hard limit on how many times we call print() avoids extremely
- // large outputs, which can be inconveniently large in some cases, but
- // we should have a better mechanism for this.
- static const size_t MaxPrints = 100;
-
- size_t prints = 0;
-
- bool exceededLimit() {
- if (prints >= MaxPrints) {
- return true;
- }
- prints++;
- return false;
- }
};
// Helper for hashing the shapes of TypeInfos and HeapTypeInfos. Keeps track of
@@ -1461,6 +1463,25 @@ size_t RecGroup::size() const {
}
}
+TypeNames DefaultTypeNameGenerator::getNames(HeapType type) {
+ auto [it, inserted] = nameCache.insert({type, {}});
+ if (inserted) {
+ // Generate a new name for this type we have not previously seen.
+ std::stringstream stream;
+ if (type.isSignature()) {
+ stream << "func." << funcCount++;
+ } else if (type.isStruct()) {
+ stream << "struct." << structCount++;
+ } else if (type.isArray()) {
+ stream << "array." << arrayCount++;
+ } else {
+ WASM_UNREACHABLE("unexpected kind");
+ }
+ it->second = {stream.str(), {}};
+ }
+ return it->second;
+}
+
template<typename T> static std::string genericToString(const T& t) {
std::ostringstream ss;
ss << t;
@@ -1473,11 +1494,18 @@ std::string Signature::toString() const { return genericToString(*this); }
std::string Struct::toString() const { return genericToString(*this); }
std::string Array::toString() const { return genericToString(*this); }
std::string Rtt::toString() const { return genericToString(*this); }
+
std::ostream& operator<<(std::ostream& os, Type type) {
return TypePrinter(os).print(type);
}
-std::ostream& operator<<(std::ostream& os, HeapType heapType) {
- return TypePrinter(os).print(heapType);
+std::ostream& operator<<(std::ostream& os, Type::Printed printed) {
+ return TypePrinter(os, printed.generateName).print(Type(printed.typeID));
+}
+std::ostream& operator<<(std::ostream& os, HeapType type) {
+ return TypePrinter(os).print(type);
+}
+std::ostream& operator<<(std::ostream& os, HeapType::Printed printed) {
+ return TypePrinter(os, printed.generateName).print(HeapType(printed.typeID));
}
std::ostream& operator<<(std::ostream& os, Tuple tuple) {
return TypePrinter(os).print(tuple);
@@ -1944,22 +1972,21 @@ std::optional<Rtt> TypeBounder::lub(const Rtt& a, const Rtt& b) {
return Rtt(depth, a.heapType);
}
-template<typename T, typename F>
-std::ostream& TypePrinter::printChild(T curr, F printer) {
- if (exceededLimit()) {
- return os << "..!";
+void TypePrinter::printHeapTypeName(HeapType type) {
+ if (type.isBasic()) {
+ print(type);
+ return;
}
- auto it = depths.find(curr.getID());
- if (it != depths.end()) {
- assert(it->second <= currDepth);
- size_t relativeDepth = currDepth - it->second;
- return os << "..." << relativeDepth;
+ os << '$' << generator(type).name;
+}
+
+void TypePrinter::printSupertypeOr(std::optional<HeapType> super,
+ std::string other) {
+ if (super) {
+ printHeapTypeName(*super);
+ } else {
+ os << other;
}
- depths[curr.getID()] = ++currDepth;
- printer();
- depths.erase(curr.getID());
- --currDepth;
- return os;
}
std::ostream& TypePrinter::print(Type type) {
@@ -1994,33 +2021,32 @@ std::ostream& TypePrinter::print(Type type) {
}
}
- return printChild(type, [&]() {
- if (isTemp(type)) {
- os << "[T]";
- }
+ if (isTemp(type)) {
+ os << "(; temp ;) ";
+ }
#if TRACE_CANONICALIZATION
- os << "[" << ((type.getID() >> 4) % 1000) << "]";
+ os << "(;" << ((type.getID() >> 4) % 1000) << ";) ";
#endif
- if (type.isTuple()) {
- print(type.getTuple());
- } else if (type.isRef()) {
- os << "(ref ";
- if (type.isNullable()) {
- os << "null ";
- }
- print(type.getHeapType());
- os << ')';
- } else if (type.isRtt()) {
- print(type.getRtt());
- } else {
- WASM_UNREACHABLE("unexpected type");
- }
- });
+ if (type.isTuple()) {
+ print(type.getTuple());
+ } else if (type.isRef()) {
+ os << "(ref ";
+ if (type.isNullable()) {
+ os << "null ";
+ }
+ printHeapTypeName(type.getHeapType());
+ os << ')';
+ } else if (type.isRtt()) {
+ print(type.getRtt());
+ } else {
+ WASM_UNREACHABLE("unexpected type");
+ }
+ return os;
}
-std::ostream& TypePrinter::print(HeapType heapType) {
- if (heapType.isBasic()) {
- switch (heapType.getBasic()) {
+std::ostream& TypePrinter::print(HeapType type) {
+ if (type.isBasic()) {
+ switch (type.getBasic()) {
case HeapType::func:
return os << "func";
case HeapType::ext:
@@ -2036,29 +2062,25 @@ std::ostream& TypePrinter::print(HeapType heapType) {
}
}
- return printChild(heapType, [&]() {
- if (isTemp(heapType)) {
- os << "[T]";
- }
+ if (isTemp(type)) {
+ os << "(; temp ;) ";
+ }
#if TRACE_CANONICALIZATION
- os << "[" << ((heapType.getID() >> 4) % 1000) << "]";
- if (auto super = heapType.getSuperType()) {
- os << "[super " << ((super->getID() >> 4) % 1000) << "]";
- }
+ os << "(;" << ((type.getID() >> 4) % 1000) << ";)";
#endif
- if (getHeapTypeInfo(heapType)->kind == HeapTypeInfo::BasicKind) {
- os << '*';
- print(getHeapTypeInfo(heapType)->basic);
- } else if (heapType.isSignature()) {
- print(heapType.getSignature());
- } else if (heapType.isStruct()) {
- print(heapType.getStruct());
- } else if (heapType.isArray()) {
- print(heapType.getArray());
- } else {
- WASM_UNREACHABLE("unexpected type");
- }
- });
+ if (getHeapTypeInfo(type)->kind == HeapTypeInfo::BasicKind) {
+ os << "(; noncanonical ;) ";
+ print(getHeapTypeInfo(type)->basic);
+ } else if (type.isSignature()) {
+ print(type.getSignature(), type.getSuperType());
+ } else if (type.isStruct()) {
+ print(type.getStruct(), type.getSuperType());
+ } else if (type.isArray()) {
+ print(type.getArray(), type.getSuperType());
+ } else {
+ WASM_UNREACHABLE("unexpected type");
+ }
+ return os;
}
std::ostream& TypePrinter::print(const Tuple& tuple) {
@@ -2094,7 +2116,8 @@ std::ostream& TypePrinter::print(const Field& field) {
return os;
}
-std::ostream& TypePrinter::print(const Signature& sig) {
+std::ostream& TypePrinter::print(const Signature& sig,
+ std::optional<HeapType> super) {
auto printPrefixed = [&](const char* prefix, Type type) {
os << '(' << prefix;
for (Type t : type) {
@@ -2105,6 +2128,9 @@ std::ostream& TypePrinter::print(const Signature& sig) {
};
os << "(func";
+ if (printSupertypes) {
+ os << "_subtype";
+ }
if (sig.params.getID() != Type::none) {
os << ' ';
printPrefixed("param", sig.params);
@@ -2113,11 +2139,19 @@ std::ostream& TypePrinter::print(const Signature& sig) {
os << ' ';
printPrefixed("result", sig.results);
}
+ if (printSupertypes) {
+ os << ' ';
+ printSupertypeOr(super, "func");
+ }
return os << ')';
}
-std::ostream& TypePrinter::print(const Struct& struct_) {
+std::ostream& TypePrinter::print(const Struct& struct_,
+ std::optional<HeapType> super) {
os << "(struct";
+ if (printSupertypes) {
+ os << "_subtype";
+ }
if (struct_.fields.size()) {
os << " (field";
}
@@ -2128,12 +2162,25 @@ std::ostream& TypePrinter::print(const Struct& struct_) {
if (struct_.fields.size()) {
os << ')';
}
+ if (printSupertypes) {
+ os << ' ';
+ printSupertypeOr(super, "data");
+ }
return os << ')';
}
-std::ostream& TypePrinter::print(const Array& array) {
- os << "(array ";
+std::ostream& TypePrinter::print(const Array& array,
+ std::optional<HeapType> super) {
+ os << "(array";
+ if (printSupertypes) {
+ os << "_subtype";
+ }
+ os << ' ';
print(array.element);
+ if (printSupertypes) {
+ os << ' ';
+ printSupertypeOr(super, "data");
+ }
return os << ')';
}
@@ -2142,7 +2189,7 @@ std::ostream& TypePrinter::print(const Rtt& rtt) {
if (rtt.hasDepth()) {
os << rtt.depth << ' ';
}
- print(rtt.heapType);
+ printHeapTypeName(rtt.heapType);
return os << ')';
}
diff --git a/test/example/type-builder-nominal.cpp b/test/example/type-builder-nominal.cpp
index 470415fa6..f83648b74 100644
--- a/test/example/type-builder-nominal.cpp
+++ b/test/example/type-builder-nominal.cpp
@@ -1,6 +1,7 @@
#include <cassert>
#include <iostream>
+#include "wasm-type-printing.h"
#include "wasm-type.h"
using namespace wasm;
@@ -29,23 +30,31 @@ void test_builder() {
Struct struct_({Field(refNullArray, Immutable), Field(rttArray, Mutable)});
Array array(Field(refNullExt, Mutable));
+ IndexedTypeNameGenerator print(builder);
+
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";
+ 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::cout << "(rtt 0 $array) => " << print(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::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::cout << "(rtt 0 $array) => " << print(rttArray) << "\n\n";
std::vector<HeapType> built = *builder.build();
@@ -55,12 +64,17 @@ void test_builder() {
Type newRefNullArray = Type(built[2], Nullable);
Type newRttArray = Type(Rtt(0, built[2]));
+ print = IndexedTypeNameGenerator(built);
+
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";
+ 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";
+ std::cout << "(rtt 0 $array) => " << print(newRttArray) << "\n\n";
}
// Check that the builder works when there are duplicate definitions
@@ -161,7 +175,8 @@ void test_recursive() {
builder[0] = Signature(Type::none, temp);
built = *builder.build();
}
- std::cout << built[0] << "\n\n";
+ 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);
}
@@ -177,8 +192,9 @@ void test_recursive() {
builder[1] = Signature(Type::none, temp0);
built = *builder.build();
}
- std::cout << built[0] << "\n";
- std::cout << built[1] << "\n\n";
+ 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]);
@@ -201,11 +217,12 @@ void test_recursive() {
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";
+ 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]);
@@ -243,12 +260,13 @@ void test_recursive() {
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";
+ 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]);
@@ -270,8 +288,9 @@ void test_recursive() {
builder[1] = Signature(Type::none, temp0);
built = *builder.build();
}
- std::cout << built[0] << "\n";
- std::cout << built[1] << "\n\n";
+ 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]);
diff --git a/test/example/type-builder-nominal.txt b/test/example/type-builder-nominal.txt
index ff3e1c5fe..8d1fe67e4 100644
--- a/test/example/type-builder-nominal.txt
+++ b/test/example/type-builder-nominal.txt
@@ -1,96 +1,114 @@
;; 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))
+$sig => (; temp ;) (func_subtype func)
+$struct => (; temp ;) (func_subtype func)
+$array => (; temp ;) (func_subtype func)
+(ref $sig) => (; temp ;) (ref $0)
+(ref $struct) => (; temp ;) (ref $1)
+(ref $array) => (; temp ;) (ref $2)
+(ref null $array) => (; temp ;) (ref null $2)
+(rtt 0 $array) => (; temp ;) (rtt 0 $2)
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)))
+$sig => (; temp ;) (func_subtype (param (; temp ;) (ref $1)) (result (; temp ;) (ref $2) i32) func)
+$struct => (; temp ;) (struct_subtype (field (; temp ;) (ref null $2) (mut (; temp ;) (rtt 0 $2))) data)
+$array => (; temp ;) (array_subtype (mut externref) data)
+(ref $sig) => (; temp ;) (ref $0)
+(ref $struct) => (; temp ;) (ref $1)
+(ref $array) => (; temp ;) (ref $2)
+(ref null $array) => (; temp ;) (ref null $2)
+(rtt 0 $array) => (; temp ;) (rtt 0 $2)
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)))
+$sig => (func_subtype (param (ref $1)) (result (ref $2) i32) func)
+$struct => (struct_subtype (field (ref null $2) (mut (rtt 0 $2))) data)
+$array => (array_subtype (mut externref) data)
+(ref $sig) => (ref $0)
+(ref $struct) => (ref $1)
+(ref $array) => (ref $2)
+(ref null $array) => (ref null $2)
+(rtt 0 $array) => (rtt 0 $2)
;; Test canonicalization
;; Test basic
;; Test canonical signatures
;; Test recursive types
-(func (result (ref null ...1)))
+(func_subtype (result (ref null $0)) func)
-(func (result (ref null (func (result (ref null ...3))))))
-(func (result (ref null (func (result (ref null ...3))))))
+(func_subtype (result (ref null $1)) func)
+(func_subtype (result (ref null $0)) func)
-(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_subtype (result (ref null $1)) func)
+(func_subtype (result (ref null $2)) func)
+(func_subtype (result (ref null $3)) func)
+(func_subtype (result (ref null $4)) func)
+(func_subtype (result (ref null $0)) func)
-(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_subtype (result (ref null $0) (ref null $2)) func)
+(func_subtype (result (ref null $1) (ref null $3)) func)
+(func_subtype func)
+(func_subtype func)
+(func_subtype (result (ref null $0)) func)
+(func_subtype (result (ref null $1)) func)
-(func (result (ref null ...1)))
-(func (result (ref null (func (result ...1)))))
+(func_subtype (result (ref null $0)) func)
+(func_subtype (result (ref null $0)) func)
;; 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))
+$sig => (; temp ;) (func_subtype func)
+$struct => (; temp ;) (func_subtype func)
+$array => (; temp ;) (func_subtype func)
+(ref $sig) => (; temp ;) (ref $0)
+(ref $struct) => (; temp ;) (ref $1)
+(ref $array) => (; temp ;) (ref $2)
+(ref null $array) => (; temp ;) (ref null $2)
+(rtt 0 $array) => (; temp ;) (rtt 0 $2)
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)))
+$sig => (; temp ;) (func_subtype (param (; temp ;) (ref $1)) (result (; temp ;) (ref $2) i32) func)
+$struct => (; temp ;) (struct_subtype (field (; temp ;) (ref null $2) (mut (; temp ;) (rtt 0 $2))) data)
+$array => (; temp ;) (array_subtype (mut externref) data)
+(ref $sig) => (; temp ;) (ref $0)
+(ref $struct) => (; temp ;) (ref $1)
+(ref $array) => (; temp ;) (ref $2)
+(ref null $array) => (; temp ;) (ref null $2)
+(rtt 0 $array) => (; temp ;) (rtt 0 $2)
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)))
+$sig => (func_subtype (param (ref $1)) (result (ref $2) i32) func)
+$struct => (struct_subtype (field (ref null $2) (mut (rtt 0 $2))) data)
+$array => (array_subtype (mut externref) data)
+(ref $sig) => (ref $0)
+(ref $struct) => (ref $1)
+(ref $array) => (ref $2)
+(ref null $array) => (ref null $2)
+(rtt 0 $array) => (rtt 0 $2)
;; Test canonicalization
;; Test basic
;; Test canonical signatures
;; 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)))))
+(func_subtype (result (ref null $0)) func)
+
+(func_subtype (result (ref null $1)) func)
+(func_subtype (result (ref null $0)) func)
+
+(func_subtype (result (ref null $1)) func)
+(func_subtype (result (ref null $2)) func)
+(func_subtype (result (ref null $3)) func)
+(func_subtype (result (ref null $4)) func)
+(func_subtype (result (ref null $0)) func)
+
+(func_subtype (result (ref null $0) (ref null $2)) func)
+(func_subtype (result (ref null $1) (ref null $3)) func)
+(func_subtype func)
+(func_subtype func)
+(func_subtype (result (ref null $0)) func)
+(func_subtype (result (ref null $1)) func)
+
+(func_subtype (result (ref null $0)) func)
+(func_subtype (result (ref null $0)) func)
;; Test subtyping
diff --git a/test/example/type-builder.cpp b/test/example/type-builder.cpp
index 3c6c8eeda..318e48f2e 100644
--- a/test/example/type-builder.cpp
+++ b/test/example/type-builder.cpp
@@ -1,6 +1,7 @@
#include <cassert>
#include <iostream>
+#include "wasm-type-printing.h"
#include "wasm-type.h"
using namespace wasm;
@@ -77,7 +78,8 @@ void test_recursive() {
builder[0] = Signature(Type::none, temp);
built = *builder.build();
}
- std::cout << built[0] << "\n\n";
+ 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);
}
@@ -93,8 +95,9 @@ void test_recursive() {
builder[1] = Signature(Type::none, temp0);
built = *builder.build();
}
- std::cout << built[0] << "\n";
- std::cout << built[1] << "\n\n";
+ 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]);
@@ -117,11 +120,12 @@ void test_recursive() {
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";
+ 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]);
@@ -153,12 +157,13 @@ void test_recursive() {
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";
+ 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]);
@@ -180,8 +185,9 @@ void test_recursive() {
builder[1] = Signature(Type::none, temp0);
built = *builder.build();
}
- std::cout << built[0] << "\n";
- std::cout << built[1] << "\n\n";
+ 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]);
@@ -199,8 +205,9 @@ void test_recursive() {
builder[2] = HeapType::any;
built = *builder.build();
}
- std::cout << built[0] << "\n";
- std::cout << built[1] << "\n\n";
+ 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].getSignature().params == Type::anyref);
diff --git a/test/example/type-builder.txt b/test/example/type-builder.txt
index df67b599d..372e531a1 100644
--- a/test/example/type-builder.txt
+++ b/test/example/type-builder.txt
@@ -1,56 +1,56 @@
;; Test canonicalization
;; Test basic
;; Test recursive types
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1) (ref null (func))))
-(func (result (ref null ...1) (ref null (func))))
+(func (result (ref null $0) (ref null $2)))
+(func (result (ref null $0) (ref null $2)))
(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 $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (param anyref) (result (ref null ...1)))
-(func (param anyref) (result (ref null ...1)))
+(func (param anyref) (result (ref null $0)))
+(func (param anyref) (result (ref null $0)))
;; Test LUBs
;; Test canonicalization
;; Test basic
;; Test recursive types
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1) (ref null (func))))
-(func (result (ref null ...1) (ref null (func))))
+(func (result (ref null $0) (ref null $2)))
+(func (result (ref null $0) (ref null $2)))
(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 $0)))
+(func (result (ref null $0)))
-(func (result (ref null ...1)))
-(func (result (ref null ...1)))
+(func (result (ref null $0)))
+(func (result (ref null $0)))
-(func (param anyref) (result (ref null ...1)))
-(func (param anyref) (result (ref null ...1)))
+(func (param anyref) (result (ref null $0)))
+(func (param anyref) (result (ref null $0)))
;; Test LUBs
diff --git a/test/example/typeinfo.cpp b/test/example/typeinfo.cpp
index ae40ad188..dd8e13d43 100644
--- a/test/example/typeinfo.cpp
+++ b/test/example/typeinfo.cpp
@@ -317,7 +317,6 @@ void test_printing() {
std::cout << tuple << "\n";
std::cout << Type(tuple) << "\n";
}
- // TODO: Think about recursive types. Currently impossible to construct.
{
std::cout << "\n;; Recursive (not really)\n";
Signature signatureSignature(Type::none, Type::none);
diff --git a/test/example/typeinfo.txt b/test/example/typeinfo.txt
index c205ce431..552e59e58 100644
--- a/test/example/typeinfo.txt
+++ b/test/example/typeinfo.txt
@@ -20,27 +20,27 @@ i31ref
;; Signature
(func)
-(ref (func))
-(ref null (func))
+(ref $func.0)
+(ref null $func.0)
(func (param i32) (result f64))
-(ref (func (param i32) (result f64)))
-(ref null (func (param i32) (result f64)))
+(ref $func.0)
+(ref null $func.0)
;; Struct
(struct)
-(ref (struct))
-(ref null (struct))
+(ref $struct.0)
+(ref null $struct.0)
(struct (field i32 i64 (mut f32) (mut f64) externref))
-(ref (struct (field i32 i64 (mut f32) (mut f64) externref)))
-(ref null (struct (field i32 i64 (mut f32) (mut f64) externref)))
+(ref $struct.0)
+(ref null $struct.0)
;; Array
(array i32)
-(ref (array i32))
-(ref null (array i32))
+(ref $array.0)
+(ref null $array.0)
(array (mut externref))
-(ref (array (mut externref)))
-(ref null (array (mut externref)))
+(ref $array.0)
+(ref null $array.0)
;; Tuple
()
@@ -59,50 +59,50 @@ none
(rtt 3 eq)
(rtt 4 i31)
(rtt 4 i31)
-(rtt 6 (func))
-(rtt 6 (func))
-(rtt 7 (struct))
-(rtt 7 (struct))
-(rtt 8 (array i32))
-(rtt 8 (array i32))
+(rtt 6 $func.0)
+(rtt 6 $func.0)
+(rtt 7 $struct.0)
+(rtt 7 $struct.0)
+(rtt 8 $array.0)
+(rtt 8 $array.0)
;; Signature of references (param/result)
-(func (param (ref null (struct))) (result (ref (array (mut i32)))))
+(func (param (ref null $struct.0)) (result (ref $array.0)))
;; Signature of references (params/results)
-(func (param (ref null (struct)) (ref (array (mut i32)))) (result (ref (struct)) (ref null (array i32))))
+(func (param (ref null $struct.0) (ref $array.0)) (result (ref $struct.0) (ref null $array.1)))
;; Struct of references
-(struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func)))))
-(ref (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func))))))
-(ref null (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func))))))
-(struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct)))))
-(ref (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct))))))
-(ref null (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct))))))
-(struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32)))))
-(ref (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32))))))
-(ref null (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32))))))
-(struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32))))))
-(ref (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32)))))))
-(ref null (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32)))))))
+(struct (field (ref $func.0) (mut (ref $func.0)) (ref null $func.0) (mut (ref null $func.0))))
+(ref $struct.0)
+(ref null $struct.0)
+(struct (field (ref $struct.0) (mut (ref $struct.0)) (ref null $struct.0) (mut (ref null $struct.0))))
+(ref $struct.0)
+(ref null $struct.0)
+(struct (field (ref $array.0) (mut (ref $array.0)) (ref null $array.0) (mut (ref null $array.0))))
+(ref $struct.0)
+(ref null $struct.0)
+(struct (field (mut i32) (mut (ref null $func.0)) (mut (ref null $struct.0)) (mut (ref null $array.0))))
+(ref $struct.0)
+(ref null $struct.0)
;; Array of references
-(array (ref null (func)))
-(ref (array (ref null (func))))
-(ref null (array (ref null (func))))
-(array (mut (ref null (struct))))
-(ref (array (mut (ref null (struct)))))
-(ref null (array (mut (ref null (struct)))))
-(array (ref null (array i32)))
-(ref (array (ref null (array i32))))
-(ref null (array (ref null (array i32))))
+(array (ref null $func.0))
+(ref $array.0)
+(ref null $array.0)
+(array (mut (ref null $struct.0)))
+(ref $array.0)
+(ref null $array.0)
+(array (ref null $array.0))
+(ref $array.0)
+(ref null $array.0)
;; Tuple of references
-((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32)))
-((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32)))
+((ref $func.0) (ref null $func.0) (ref $struct.0) (ref null $struct.0) (ref $array.0) (ref null $array.0))
+((ref $func.0) (ref null $func.0) (ref $struct.0) (ref null $struct.0) (ref $array.0) (ref null $array.0))
;; Recursive (not really)
-(func (param (ref (func))))
-(ref (func (param (ref (func)))))
-(func (param (ref (array (ref (func))))))
-(ref (func (param (ref (array (ref (func)))))))
+(func (param (ref $func.0)))
+(ref $func.0)
+(func (param (ref $array.0)))
+(ref $func.0)
diff --git a/test/lit/fuzz-types/isorecursive.test b/test/lit/fuzz-types/isorecursive.test
index 60eabec39..751f8c2a7 100644
--- a/test/lit/fuzz-types/isorecursive.test
+++ b/test/lit/fuzz-types/isorecursive.test
@@ -2,23 +2,23 @@
;; CHECK: Running with seed 0
;; CHECK-NEXT: Built 20 types:
-;; CHECK-NEXT: 0: (struct)
-;; CHECK-NEXT: 1: (func (param i31ref) (result (ref extern)))
-;; CHECK-NEXT: 2: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 3: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 4: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 5: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 6: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 7: (struct (field (mut (ref (struct (field i16 (mut i32) (mut i16)))))))
-;; CHECK-NEXT: 8: (struct (field i16 (mut i32) (mut i16)))
-;; CHECK-NEXT: 9: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 10: (struct)
-;; CHECK-NEXT: 11: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 12: (struct (field (mut i8) (rtt (struct))))
-;; CHECK-NEXT: 13: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 14: (struct (field funcref f64 (mut (rtt (struct))) (ref null (func (param i31ref) (result (ref extern)))) i8 (ref null (struct (field (mut (ref (struct (field i16 (mut i32) (mut i16))))))))))
-;; CHECK-NEXT: 15: (func (param i31ref) (result (ref extern)))
-;; CHECK-NEXT: 16: (array (mut (rtt 0 extern)))
-;; CHECK-NEXT: 17: (struct (field funcref f64 (mut (rtt (struct))) (ref null (func (param i31ref) (result (ref extern)))) i8 (ref null (struct (field (mut (ref (struct (field i16 (mut i32) (mut i16))))))))))
-;; CHECK-NEXT: 18: (struct (field (mut i8) (rtt (struct))))
-;; CHECK-NEXT: 19: (func (param i31ref) (result (ref extern)))
+;; CHECK-NEXT: (type $0 (struct_subtype data))
+;; CHECK-NEXT: (type $1 (func_subtype (param i31ref) (result (ref extern)) func))
+;; CHECK-NEXT: (type $2 (array_subtype (mut (rtt 0 extern)) data))
+;; CHECK-NEXT: (type $3 (array_subtype (mut (rtt 0 extern)) $2))
+;; CHECK-NEXT: (type $4 (array_subtype (mut (rtt 0 extern)) $2))
+;; CHECK-NEXT: (type $5 (array_subtype (mut (rtt 0 extern)) $3))
+;; CHECK-NEXT: (type $6 (array_subtype (mut (rtt 0 extern)) $3))
+;; CHECK-NEXT: (type $7 (struct_subtype (field (mut (ref $8))) $0))
+;; CHECK-NEXT: (type $8 (struct_subtype (field i16 (mut i32) (mut i16)) $0))
+;; CHECK-NEXT: (type $9 (array_subtype (mut (rtt 0 extern)) $6))
+;; CHECK-NEXT: (type $10 (struct_subtype $0))
+;; CHECK-NEXT: (type $11 (array_subtype (mut (rtt 0 extern)) $2))
+;; CHECK-NEXT: (type $12 (struct_subtype (field (mut i8) (rtt $0)) $0))
+;; CHECK-NEXT: (type $13 (array_subtype (mut (rtt 0 extern)) $6))
+;; CHECK-NEXT: (type $14 (struct_subtype (field funcref f64 (mut (rtt $10)) (ref null $15) i8 (ref null $7)) $10))
+;; CHECK-NEXT: (type $15 (func_subtype (param i31ref) (result (ref extern)) $1))
+;; CHECK-NEXT: (type $16 (array_subtype (mut (rtt 0 extern)) $2))
+;; CHECK-NEXT: (type $17 (struct_subtype (field funcref f64 (mut (rtt $10)) (ref null $15) i8 (ref null $7)) $14))
+;; CHECK-NEXT: (type $18 (struct_subtype (field (mut i8) (rtt $0)) $12))
+;; CHECK-NEXT: (type $19 (func_subtype (param i31ref) (result (ref extern)) $15))
diff --git a/test/lit/fuzz-types/nominal.test b/test/lit/fuzz-types/nominal.test
index 5b403c23a..8ca330adf 100644
--- a/test/lit/fuzz-types/nominal.test
+++ b/test/lit/fuzz-types/nominal.test
@@ -1,23 +1,24 @@
;; RUN: wasm-fuzz-types --nominal -v --seed=0 | filecheck %s
-;; CHECK: Built 20 types:
-;; CHECK-NEXT: 0: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...5 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...9 (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ..!))) i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!))))))
-;; CHECK-NEXT: 1: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt (func (param ...5)))) (ref (struct (field (mut (rtt (func (param ...7)))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param ...5)))) (ref (struct (field (mut (rtt (func (param ...7)))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1))))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1)))))))))))))))
-;; CHECK-NEXT: 2: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null ...7)) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...9)) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...9)) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1)))))
-;; CHECK-NEXT: 3: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param ..!)))) ..!))))))) (mut f64)))
-;; CHECK-NEXT: 4: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut (ref null (struct (field (mut ...7) (ref ...9))))) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut (ref null (struct (field (mut ...7) (ref ...9))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...9))))))))))))))) (ref ...1)))
-;; CHECK-NEXT: 5: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref ...5)))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref ...7)))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64)))) (ref ...7)))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64)))) (ref ...9)))))))) ...1))))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref ...7)))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut ..!) (mut f64)))) ..!))))))) ..!)))))))))
-;; CHECK-NEXT: 6: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param ..!)))) ..!))))))) (mut f64)))
-;; CHECK-NEXT: 7: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...5 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...9 (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ..!))) i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!))))))
-;; CHECK-NEXT: 8: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...9))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...9))))) ...1))))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...9))))) ...1))))))))))))
-;; CHECK-NEXT: 9: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...9) (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))
-;; CHECK-NEXT: 10: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...9) (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ..!) ..! i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!)))) (mut i31ref)))
-;; CHECK-NEXT: 11: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null ...7)))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null ...9)))))))))))) ...1)))))
-;; CHECK-NEXT: 12: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...5 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...9 (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ..!))) i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!))))))
-;; CHECK-NEXT: 13: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param ..!)))) ..!))))))) (mut f64) ..!))
-;; CHECK-NEXT: 14: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...9) (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ..!) ..! i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!)))) (mut i31ref) i8))
-;; CHECK-NEXT: 15: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt (func (param ...5)))) (ref (struct (field (mut (rtt (func (param ...7)))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param ...5)))) (ref (struct (field (mut (rtt (func (param ...7)))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1))))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param ...7)))) (ref (struct (field (mut (rtt (func (param ...9)))) ...1)))))))))))))))
-;; CHECK-NEXT: 16: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1)))))
-;; CHECK-NEXT: 17: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...9) (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ..!) ..! i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!)))) (mut i31ref) i8 (mut dataref) (mut i16)))
-;; CHECK-NEXT: 18: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...5 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) ...7 i32 (mut (ref null (struct (field (mut ...7) ...9)))) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...7 (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut ...7) (mut f64) (mut (ref null (struct (field (mut ...7) (ref (struct (field (mut ...9) ...1))))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field ...9 (ref (struct (field (mut ...5) ...7 i32 (mut ...9) (mut f64) (mut (ref null (struct (field (mut ...7) ...9)))))))))))))) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ..!))) i32 (mut ..!) (mut f64)))) ..!))))))) ..! i32 (mut ..!) (mut f64) (mut ..!))))))
-;; CHECK-NEXT: 19: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref (struct (field (mut (rtt ...9)) ...1))))))) (mut f64)))) (ref (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref (struct (field (mut (rtt ...9)) ...1))))))) (mut f64) (mut (ref null (struct (field (mut (rtt ...7)) (ref (struct (field (mut (rtt ...9)) ...1)))))))))))))))
+;; CHECK: Running with seed 0
+;; CHECK-NEXT: Built 20 types:
+;; CHECK-NEXT: (type $0 (struct_subtype (field (ref null $9) (ref $5)) data))
+;; CHECK-NEXT: (type $1 (func_subtype (param (rtt 0 $8)) func))
+;; CHECK-NEXT: (type $2 (struct_subtype (field (mut (rtt $19)) (ref $4)) data))
+;; CHECK-NEXT: (type $3 (struct_subtype (field (mut (rtt $19)) (ref $4) i32 (mut (ref null $2)) (mut f64)) $2))
+;; CHECK-NEXT: (type $4 (struct_subtype (field (mut (rtt $19)) (ref $4)) $2))
+;; CHECK-NEXT: (type $5 (struct_subtype (field (mut (rtt $19)) (ref $4) i32 (mut (ref null $2)) (mut f64) (mut (ref null $11))) $3))
+;; CHECK-NEXT: (type $6 (struct_subtype (field (mut (rtt $19)) (ref $4) i32 (mut (ref null $2)) (mut f64)) $3))
+;; CHECK-NEXT: (type $7 (struct_subtype (field (ref null $9) (ref $5)) $0))
+;; CHECK-NEXT: (type $8 (struct_subtype (field (ref null $9) (ref $5)) $0))
+;; CHECK-NEXT: (type $9 (struct_subtype (field (mut (rtt $19)) (ref $4) i32 (mut (ref null $2)) (mut f64)) $6))
+;; CHECK-NEXT: (type $10 (struct_subtype (field (ref $9) (ref $5) (mut i31ref)) $0))
+;; CHECK-NEXT: (type $11 (struct_subtype (field (mut (rtt $19)) (ref $4)) $2))
+;; CHECK-NEXT: (type $12 (struct_subtype (field (ref null $9) (ref $5)) $0))
+;; CHECK-NEXT: (type $13 (struct_subtype (field (mut (rtt $19)) (ref $4) i32 (mut (ref null $2)) (mut f64) (ref null i31)) $6))
+;; CHECK-NEXT: (type $14 (struct_subtype (field (ref $9) (ref $5) (mut i31ref) i8) $10))
+;; CHECK-NEXT: (type $15 (func_subtype (param (rtt 0 $8)) $1))
+;; CHECK-NEXT: (type $16 (struct_subtype (field (mut (rtt $19)) (ref $4)) $2))
+;; CHECK-NEXT: (type $17 (struct_subtype (field (ref $9) (ref $5) (mut i31ref) i8 (mut dataref) (mut i16)) $14))
+;; CHECK-NEXT: (type $18 (struct_subtype (field (ref null $9) (ref $5)) $12))
+;; CHECK-NEXT: (type $19 (func_subtype (param (rtt 0 $8)) $15))
diff --git a/test/lit/fuzz-types/structural.test b/test/lit/fuzz-types/structural.test
index ec3968466..0d81491af 100644
--- a/test/lit/fuzz-types/structural.test
+++ b/test/lit/fuzz-types/structural.test
@@ -1,25 +1,24 @@
;; RUN: wasm-fuzz-types --structural -v --seed=0 | filecheck %s
-
;; CHECK: Running with seed 0
;; CHECK-NEXT: Built 20 types:
-;; CHECK-NEXT: 0: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))))))))
-;; CHECK-NEXT: 1: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1)))))))))))))
-;; CHECK-NEXT: 2: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) (ref ...1)))
-;; CHECK-NEXT: 3: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))
-;; CHECK-NEXT: 4: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) (ref ...1)))
-;; CHECK-NEXT: 5: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64)))) (ref ...5)))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64)))) (ref ...7)))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64)))) (ref ...7)))))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64)))) (ref ...7)))))))) (ref ...1)))))))
-;; CHECK-NEXT: 6: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))
-;; CHECK-NEXT: 7: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))))))))
-;; CHECK-NEXT: 8: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))))))))
-;; CHECK-NEXT: 9: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))
-;; CHECK-NEXT: 10: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64)))) ...5))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64)))) ...7))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ..!) ..!))))))) ..!)))) (mut f64) (mut ..!)))) (mut i31ref)))
-;; CHECK-NEXT: 11: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) (ref ...1)))
-;; CHECK-NEXT: 12: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))))))))
-;; CHECK-NEXT: 13: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64)))) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64) (ref null i31)))
-;; CHECK-NEXT: 14: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64)))) ...5))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64)))) ...7))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ..!) ..!))))))) ..!)))) (mut f64) (mut ..!)))) (mut i31ref) i8))
-;; CHECK-NEXT: 15: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1)))))))))))))
-;; CHECK-NEXT: 16: (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64)))) (ref (struct (field (mut ...5) (ref ...7) i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) (ref ...1)))
-;; CHECK-NEXT: 17: (struct (field (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...5) (ref (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut ...7) (ref ...1))))))))))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64) (mut (ref null ...7)))))))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ...7) (ref (struct (field (mut ...5) (ref ...7) i32 (mut ...7) (mut f64) (mut ...7))))))))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) (ref (struct (field (mut ...7) ...1))) i32 (mut (ref null (struct (field (mut ...7) (ref ...1))))) (mut f64)))) ...5))))))) (ref (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null (struct (field (mut ...5) ...7 i32 (mut (ref null ...7)) (mut f64)))) ...7))))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 (struct (field (ref null ..!) ..!))))))) ..!)))) (mut f64) (mut ..!)))) (mut i31ref) i8 (mut dataref) (mut i16)))
-;; CHECK-NEXT: 18: (struct (field (ref null (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...5))))) (ref (struct (field (mut (rtt (func (param (rtt 0 ...7))))) ...1))) i32 (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt (func (param (rtt 0 ...7))))) (ref ...1))))))))))
-;; CHECK-NEXT: 19: (func (param (rtt 0 (struct (field (ref null (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64)))) (ref (struct (field (mut (rtt ...5)) (ref (struct (field (mut (rtt ...7)) ...1))) i32 (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1))))) (mut f64) (mut (ref null (struct (field (mut (rtt ...7)) (ref ...1)))))))))))))
+;; CHECK-NEXT: (type $0 (struct (field (ref null $3) (ref $5))))
+;; CHECK-NEXT: (type $1 (func (param (rtt 0 $0))))
+;; CHECK-NEXT: (type $2 (struct (field (mut (rtt $1)) (ref $2))))
+;; CHECK-NEXT: (type $3 (struct (field (mut (rtt $1)) (ref $2) i32 (mut (ref null $2)) (mut f64))))
+;; CHECK-NEXT: (type $4 identical to $2)
+;; CHECK-NEXT: (type $5 (struct (field (mut (rtt $1)) (ref $2) i32 (mut (ref null $2)) (mut f64) (mut (ref null $2)))))
+;; CHECK-NEXT: (type $6 identical to $3)
+;; CHECK-NEXT: (type $7 identical to $0)
+;; CHECK-NEXT: (type $8 identical to $0)
+;; CHECK-NEXT: (type $9 identical to $3)
+;; CHECK-NEXT: (type $10 (struct (field (ref $3) (ref $5) (mut i31ref))))
+;; CHECK-NEXT: (type $11 identical to $2)
+;; CHECK-NEXT: (type $12 identical to $0)
+;; CHECK-NEXT: (type $13 (struct (field (mut (rtt $1)) (ref $2) i32 (mut (ref null $2)) (mut f64) (ref null i31))))
+;; CHECK-NEXT: (type $14 (struct (field (ref $3) (ref $5) (mut i31ref) i8)))
+;; CHECK-NEXT: (type $15 identical to $1)
+;; CHECK-NEXT: (type $16 identical to $2)
+;; CHECK-NEXT: (type $17 (struct (field (ref $3) (ref $5) (mut i31ref) i8 (mut dataref) (mut i16))))
+;; CHECK-NEXT: (type $18 identical to $0)
+;; CHECK-NEXT: (type $19 identical to $1)