diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 4 | ||||
-rw-r--r-- | src/binaryen-c.h | 4 | ||||
-rw-r--r-- | src/ir/type-updating.cpp | 3 | ||||
-rw-r--r-- | src/wasm-type.h | 8 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 11 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.c | 2 | ||||
-rw-r--r-- | test/gtest/type-builder.cpp | 86 |
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()); +} |