summaryrefslogtreecommitdiff
path: root/test/gtest
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2022-01-25 16:15:23 -0800
committerGitHub <noreply@github.com>2022-01-26 00:15:23 +0000
commit707be2b55075dccaaf0a70e23352c972fce5aa76 (patch)
treef57f7cc25a2d8b78f7261b6a5498fdcbd397f6cc /test/gtest
parentf1ff35fd413372a55d486d041cc9a795e107bad2 (diff)
downloadbinaryen-707be2b55075dccaaf0a70e23352c972fce5aa76.tar.gz
binaryen-707be2b55075dccaaf0a70e23352c972fce5aa76.tar.bz2
binaryen-707be2b55075dccaaf0a70e23352c972fce5aa76.zip
Isorecursive type validation (#4475)
When building isorecursive types, validate their relationships according to the rules described in https://github.com/WebAssembly/gc/pull/243. Specifically, supertypes must be declared before their subtypes to statically prevent cycles and child types must be declared either before or in the same recursion group as their parents.
Diffstat (limited to 'test/gtest')
-rw-r--r--test/gtest/type-builder.cpp53
1 files changed, 47 insertions, 6 deletions
diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp
index 9f1a99c5d..78c8037a4 100644
--- a/test/gtest/type-builder.cpp
+++ b/test/gtest/type-builder.cpp
@@ -155,7 +155,12 @@ static void testDirectSelfSupertype() {
const auto* error = result.getError();
ASSERT_TRUE(error);
- EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
+ if (getTypeSystem() == TypeSystem::Nominal) {
+ EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
+ } else if (getTypeSystem() == TypeSystem::Isorecursive) {
+ EXPECT_EQ(error->reason,
+ TypeBuilder::ErrorReason::ForwardSupertypeReference);
+ }
EXPECT_EQ(error->index, 0u);
}
@@ -176,7 +181,14 @@ static void testIndirectSelfSupertype() {
const auto* error = result.getError();
ASSERT_TRUE(error);
- EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
+ if (getTypeSystem() == TypeSystem::Nominal) {
+ EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::SelfSupertype);
+ } else if (getTypeSystem() == TypeSystem::Isorecursive) {
+ EXPECT_EQ(error->reason,
+ TypeBuilder::ErrorReason::ForwardSupertypeReference);
+ } else {
+ WASM_UNREACHABLE("unexpected type system");
+ }
EXPECT_EQ(error->index, 0u);
}
@@ -186,9 +198,9 @@ TEST_F(IsorecursiveTest, IndirectSelfSupertype) { testIndirectSelfSupertype(); }
static void testInvalidSupertype() {
TypeBuilder builder(2);
builder.createRecGroup(0, 2);
- builder[0] = Struct{};
- builder[1] = Struct({Field(Type::i32, Immutable)});
- builder[0].subTypeOf(builder[1]);
+ builder[0] = Struct({Field(Type::i32, Immutable)});
+ builder[1] = Struct{};
+ builder[1].subTypeOf(builder[0]);
auto result = builder.build();
EXPECT_FALSE(result);
@@ -196,8 +208,37 @@ static void testInvalidSupertype() {
const auto* error = result.getError();
ASSERT_TRUE(error);
EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::InvalidSupertype);
- EXPECT_EQ(error->index, 0u);
+ EXPECT_EQ(error->index, 1u);
}
TEST_F(NominalTest, InvalidSupertype) { testInvalidSupertype(); }
TEST_F(IsorecursiveTest, InvalidSupertype) { testInvalidSupertype(); }
+
+TEST_F(IsorecursiveTest, SelfReferencedChild) {
+ // A self-referential type should be ok even without an explicit rec group.
+ TypeBuilder builder(1);
+ Type selfRef = builder.getTempRefType(builder[0], Nullable);
+ builder[0] = Struct({Field(selfRef, Immutable)});
+ auto result = builder.build();
+ EXPECT_TRUE(result);
+}
+
+TEST_F(IsorecursiveTest, ForwardReferencedChild) {
+ TypeBuilder builder(3);
+ builder.createRecGroup(0, 2);
+ Type refA1 = builder.getTempRefType(builder[1], Nullable);
+ Type refB0 = builder.getTempRefType(builder[2], Nullable);
+ // Forward reference to same group is ok.
+ builder[0] = Struct({Field(refA1, Mutable)});
+ // Forward reference to different group is not ok.
+ builder[1] = Struct({Field(refB0, Mutable)});
+ builder[2] = Struct{};
+
+ auto result = builder.build();
+ EXPECT_FALSE(result);
+
+ const auto* error = result.getError();
+ ASSERT_TRUE(error);
+ EXPECT_EQ(error->reason, TypeBuilder::ErrorReason::ForwardChildReference);
+ EXPECT_EQ(error->index, 1u);
+}