summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--src/binaryen-c.cpp4
-rw-r--r--src/binaryen-c.h4
-rw-r--r--src/ir/type-updating.cpp3
-rw-r--r--src/wasm-type.h8
-rw-r--r--src/wasm/wasm-type.cpp11
-rw-r--r--test/example/c-api-kitchen-sink.c2
-rw-r--r--test/gtest/type-builder.cpp86
8 files changed, 103 insertions, 16 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 568753d63..03e5b3169 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ Current Trunk
-------------
- Add extra `memory64` argument for `BinaryenSetMemory` and new `BinaryenMemoryIs64` C-API method to determine 64-bit memory. (#4963)
+- `TypeBuilderSetSubType` now takes a super type as the second argument.
v110
----
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 7b06bf584..cc7ed5b15 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -6266,8 +6266,8 @@ BinaryenType TypeBuilderGetTempRefType(TypeBuilderRef builder,
}
void TypeBuilderSetSubType(TypeBuilderRef builder,
BinaryenIndex index,
- BinaryenIndex superIndex) {
- ((TypeBuilder*)builder)->setSubType(index, superIndex);
+ BinaryenHeapType superType) {
+ ((TypeBuilder*)builder)->setSubType(index, HeapType(superType));
}
void TypeBuilderCreateRecGroup(TypeBuilderRef builder,
BinaryenIndex index,
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index ba7c20126..5b343e8ba 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -3533,10 +3533,10 @@ BINARYEN_API BinaryenType TypeBuilderGetTempTupleType(TypeBuilderRef builder,
BINARYEN_API BinaryenType TypeBuilderGetTempRefType(TypeBuilderRef builder,
BinaryenHeapType heapType,
int nullable);
-// Sets the type at `index` to be a subtype of the type at `superIndex`.
+// Sets the type at `index` to be a subtype of the given super type.
BINARYEN_API void TypeBuilderSetSubType(TypeBuilderRef builder,
BinaryenIndex index,
- BinaryenIndex superIndex);
+ BinaryenHeapType superType);
// Creates a new recursion group in the range `index` inclusive to `index +
// length` exclusive. Recursion groups must not overlap.
BINARYEN_API void TypeBuilderCreateRecGroup(TypeBuilderRef builder,
diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp
index 6d5848c83..c560ce236 100644
--- a/src/ir/type-updating.cpp
+++ b/src/ir/type-updating.cpp
@@ -80,7 +80,8 @@ void GlobalTypeRewriter::update() {
// Apply a super, if there is one
if (auto super = type.getSuperType()) {
- typeBuilder.setSubType(i, indexedTypes.indices[*super]);
+ typeBuilder.setSubType(
+ i, typeBuilder.getTempHeapType(indexedTypes.indices[*super]));
}
}
diff --git a/src/wasm-type.h b/src/wasm-type.h
index 778318794..940009cbe 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -599,9 +599,9 @@ struct TypeBuilder {
Type getTempRefType(HeapType heapType, Nullability nullable);
// In nominal mode, or for nominal types, declare the HeapType being built at
- // index `i` to be an immediate subtype of the HeapType being built at index
- // `j`. Does nothing for equirecursive types.
- void setSubType(size_t i, size_t j);
+ // index `i` to be an immediate subtype of the given HeapType. Does nothing
+ // for equirecursive types.
+ void setSubType(size_t i, HeapType super);
// Create a new recursion group covering slots [i, i + length). Groups must
// not overlap or go out of bounds.
@@ -669,7 +669,7 @@ struct TypeBuilder {
}
Entry& subTypeOf(Entry other) {
assert(&builder == &other.builder);
- builder.setSubType(index, other.index);
+ builder.setSubType(index, other);
return *this;
}
};
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 1bced53e4..c77099a1d 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -2803,11 +2803,10 @@ Type TypeBuilder::getTempRefType(HeapType type, Nullability nullable) {
return markTemp(impl->typeStore.insert(TypeInfo(type, nullable)));
}
-void TypeBuilder::setSubType(size_t i, size_t j) {
- assert(i < size() && j < size() && "index out of bounds");
+void TypeBuilder::setSubType(size_t i, HeapType super) {
+ assert(i < size() && "index out of bounds");
HeapTypeInfo* sub = impl->entries[i].info.get();
- HeapTypeInfo* super = impl->entries[j].info.get();
- sub->supertype = super;
+ sub->supertype = getHeapTypeInfo(super);
}
void TypeBuilder::createRecGroup(size_t i, size_t length) {
@@ -3657,9 +3656,9 @@ std::optional<TypeBuilder::Error> canonicalizeIsorecursive(
if (type.isBasic()) {
continue;
}
- // Validate the supertype. Supertypes must precede their subtypes.
+ // Validate the supertype. Temporary supertypes must precede their subtypes.
if (auto super = type.getSuperType()) {
- if (!indexOfType.count(*super)) {
+ if (isTemp(*super) && !indexOfType.count(*super)) {
return {{index, TypeBuilder::ErrorReason::ForwardSupertypeReference}};
}
}
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index 267e0763d..bc6b4b873 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -2161,7 +2161,7 @@ void test_typebuilder() {
fieldMutables,
2);
}
- TypeBuilderSetSubType(builder, tempSubStructIndex, tempStructIndex);
+ TypeBuilderSetSubType(builder, tempSubStructIndex, tempStructHeapType);
// TODO: Rtts (post-MVP?)
diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp
index 4b282ea7c..525a45c31 100644
--- a/test/gtest/type-builder.cpp
+++ b/test/gtest/type-builder.cpp
@@ -533,3 +533,89 @@ TEST_F(NominalTest, TestSubTypes) {
auto subTypes1 = subTypes.getStrictSubTypes(built[1]);
EXPECT_EQ(subTypes1.size(), 0u);
}
+
+// 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) {
+ // Build an initial type A1
+ Type A1;
+ {
+ TypeBuilder builder(1);
+ builder[0] = Struct();
+ auto result = builder.build();
+ ASSERT_TRUE(result);
+ auto built = *result;
+ A1 = Type(built[0], Nullable);
+ }
+
+ // Build a separate type A2 identical to A1
+ Type A2;
+ {
+ TypeBuilder builder(1);
+ builder[0] = Struct();
+ auto result = builder.build();
+ ASSERT_TRUE(result);
+ auto built = *result;
+ A2 = Type(built[0], Nullable);
+ }
+
+ // Build a type B1 <: A1 using a new builder
+ Type B1;
+ {
+ TypeBuilder builder(1);
+ builder[0] = Struct();
+ builder.setSubType(0, A1.getHeapType());
+ auto result = builder.build();
+ ASSERT_TRUE(result);
+ auto built = *result;
+ B1 = Type(built[0], Nullable);
+ }
+
+ // Build a type B2 <: A2 using a new builder
+ Type B2;
+ {
+ TypeBuilder builder(1);
+ builder[0] = Struct();
+ builder.setSubType(0, A2.getHeapType());
+ auto result = builder.build();
+ ASSERT_TRUE(result);
+ auto built = *result;
+ B2 = Type(built[0], Nullable);
+ }
+
+ // Test that A1 == A2 and B1 == B2
+ EXPECT_EQ(A1.getHeapType(), A2.getHeapType());
+ EXPECT_EQ(B1.getHeapType(), B2.getHeapType());
+}