Skip to content

Commit 6c4214f

Browse files
authored
Require matching finality in descriptor types (#9068)
See WebAssembly/custom-descriptors#61.
1 parent e7a4551 commit 6c4214f

11 files changed

Lines changed: 264 additions & 142 deletions

src/tools/fuzzing/heap-types.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,14 @@ struct HeapTypeGeneratorImpl {
286286
void populateTypes() {
287287
// Create the heap types.
288288
for (; index < builder.size(); ++index) {
289-
// Types without nontrivial subtypes may be marked final.
290-
builder[index].setOpen(subtypeIndices[index].size() > 1 || rand.oneIn(2));
289+
// Types without nontrivial subtypes may be marked final. Descriptors
290+
// must have the same finality as their described types.
291+
if (describedIndices[index]) {
292+
builder[index].setOpen(builder[*describedIndices[index]].isOpen());
293+
} else {
294+
builder[index].setOpen(subtypeIndices[index].size() > 1 ||
295+
rand.oneIn(2));
296+
}
291297
auto kind = typeKinds[index];
292298
auto share = HeapType(builder[index]).getShared();
293299
bool isDesc = describedIndices[index].has_value();

src/wasm-type.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ struct TypeBuilder {
910910
void createRecGroup(size_t i, size_t length);
911911

912912
void setOpen(size_t i, bool open = true);
913+
bool isOpen(size_t i) const;
913914
void setShared(size_t i, Shareability share = Shared);
914915

915916
enum class ErrorReasonKind {
@@ -947,6 +948,8 @@ struct TypeBuilder {
947948
InvalidUnsharedDescribes,
948949
// The custom descriptors feature is missing.
949950
RequiresCustomDescriptors,
951+
// The descriptor and described types have mismatched finality.
952+
MismatchedDescriptorFinality,
950953
// Two rec groups with different shapes would have the same shapes after
951954
// the binary writer generalizes refined types that use disabled features.
952955
RecGroupCollision,
@@ -1036,6 +1039,7 @@ struct TypeBuilder {
10361039
builder.setOpen(index, open);
10371040
return *this;
10381041
}
1042+
bool isOpen() const { return builder.isOpen(index); }
10391043
Entry& setShared(Shareability share = Shared) {
10401044
builder.setShared(index, share);
10411045
return *this;

src/wasm/wasm-type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,8 @@ std::ostream& operator<<(std::ostream& os,
14871487
return os << "Heap type describes an invalid unshared type";
14881488
case TypeBuilder::ErrorReasonKind::RequiresCustomDescriptors:
14891489
return os << "custom descriptors required but not enabled";
1490+
case TypeBuilder::ErrorReasonKind::MismatchedDescriptorFinality:
1491+
return os << "Descriptor and described types have mismatched finality";
14901492
case TypeBuilder::ErrorReasonKind::RecGroupCollision:
14911493
return os
14921494
<< "distinct rec groups would be identical after binary writing";
@@ -2284,6 +2286,11 @@ void TypeBuilder::setOpen(size_t i, bool open) {
22842286
impl->entries[i].info->isOpen = open;
22852287
}
22862288

2289+
bool TypeBuilder::isOpen(size_t i) const {
2290+
assert(i < size() && "index out of bounds");
2291+
return impl->entries[i].info->isOpen;
2292+
}
2293+
22872294
void TypeBuilder::setShared(size_t i, Shareability share) {
22882295
assert(i < size() && "index out of bounds");
22892296
impl->entries[i].info->share = share;
@@ -2608,6 +2615,10 @@ buildRecGroup(std::unique_ptr<RecGroupInfo>&& groupInfo,
26082615
return {TypeBuilder::Error{
26092616
i, TypeBuilder::ErrorReasonKind::ForwardDescriptorReference}};
26102617
}
2618+
if (type.isOpen() != desc->isOpen()) {
2619+
return {TypeBuilder::Error{
2620+
i, TypeBuilder::ErrorReasonKind::MismatchedDescriptorFinality}};
2621+
}
26112622
}
26122623
// Describes clauses were already checked as we validated each type in the
26132624
// group.

test/gtest/type-builder.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,70 @@ TEST_F(TypeTest, CanonicalizeDescriptors) {
585585
EXPECT_NE(built[0].getRecGroup(), built[4].getRecGroup());
586586
}
587587

588+
TEST_F(TypeTest, MismatchedDescriptorFinality) {
589+
// Described type is final, descriptor type is open.
590+
{
591+
TypeBuilder builder(2);
592+
builder.createRecGroup(0, 2);
593+
builder[0] = Struct{};
594+
builder[1].setOpen() = Struct{};
595+
builder[0].descriptor(builder[1]);
596+
builder[1].describes(builder[0]);
597+
598+
auto result = builder.build();
599+
EXPECT_FALSE(result);
600+
const auto* error = result.getError();
601+
ASSERT_TRUE(error);
602+
EXPECT_EQ(error->reason,
603+
TypeBuilder::ErrorReasonKind::MismatchedDescriptorFinality);
604+
EXPECT_EQ(error->index, 0u);
605+
}
606+
607+
// Described type is open, descriptor type is final.
608+
{
609+
TypeBuilder builder(2);
610+
builder.createRecGroup(0, 2);
611+
builder[0].setOpen() = Struct{};
612+
builder[1] = Struct{};
613+
builder[0].descriptor(builder[1]);
614+
builder[1].describes(builder[0]);
615+
616+
auto result = builder.build();
617+
EXPECT_FALSE(result);
618+
const auto* error = result.getError();
619+
ASSERT_TRUE(error);
620+
EXPECT_EQ(error->reason,
621+
TypeBuilder::ErrorReasonKind::MismatchedDescriptorFinality);
622+
EXPECT_EQ(error->index, 0u);
623+
}
624+
625+
// Both are final: succeeds.
626+
{
627+
TypeBuilder builder(2);
628+
builder.createRecGroup(0, 2);
629+
builder[0] = Struct{};
630+
builder[1] = Struct{};
631+
builder[0].descriptor(builder[1]);
632+
builder[1].describes(builder[0]);
633+
634+
auto result = builder.build();
635+
EXPECT_TRUE(result);
636+
}
637+
638+
// Both are open: succeeds.
639+
{
640+
TypeBuilder builder(2);
641+
builder.createRecGroup(0, 2);
642+
builder[0].setOpen() = Struct{};
643+
builder[1].setOpen() = Struct{};
644+
builder[0].descriptor(builder[1]);
645+
builder[1].describes(builder[0]);
646+
647+
auto result = builder.build();
648+
EXPECT_TRUE(result);
649+
}
650+
}
651+
588652
TEST_F(TypeTest, CanonicalizeFinal) {
589653
// Types are different if their finality flag is different.
590654
TypeBuilder builder(2);

test/lit/ctor-eval/gc-desc.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
;; CHECK: (rec
77
;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct)))
88
(type $struct (sub (descriptor $desc) (struct)))
9-
;; CHECK: (type $desc (describes $struct) (struct))
10-
(type $desc (describes $struct) (struct))
9+
;; CHECK: (type $desc (sub (describes $struct) (struct)))
10+
(type $desc (sub (describes $struct) (struct)))
1111
)
1212
;; CHECK: (type $2 (func))
1313

test/lit/fuzz-types.test

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,28 @@
55
;; CHECK-NEXT: (rec
66
;; CHECK-NEXT: (type $0 (sub (shared (func (param i64 f64 exnref (ref null $0)) (result (ref cont))))))
77
;; CHECK-NEXT: (type $1 (shared (descriptor $2) (struct)))
8-
;; CHECK-NEXT: (type $2 (shared (describes $1) (descriptor $4) (struct)))
9-
;; CHECK-NEXT: (type $3 (sub (array (mut (ref null $0)))))
10-
;; CHECK-NEXT: (type $4 (sub (shared (describes $2) (struct (field (mut i8)) (field (ref null $1)) (field (mut v128)) (field (mut (ref (shared any))))))))
8+
;; CHECK-NEXT: (type $2 (shared (describes $1) (descriptor $4) (struct (field (mut v128)) (field (mut (ref $4))) (field (mut v128)) (field (mut i32)) (field f32))))
9+
;; CHECK-NEXT: (type $3 (array i8))
10+
;; CHECK-NEXT: (type $4 (shared (describes $2) (struct)))
1111
;; CHECK-NEXT: )
1212
;; CHECK-NEXT: (rec
13-
;; CHECK-NEXT: (type $5 (shared (descriptor $6) (struct)))
14-
;; CHECK-NEXT: (type $6 (sub (shared (describes $5) (descriptor $7) (struct (field (mut i8)) (field (mut i32)) (field (mut i64))))))
15-
;; CHECK-NEXT: (type $7 (sub (shared (describes $6) (descriptor $9) (struct (field (mut i64)) (field f32) (field i16) (field (mut f32))))))
16-
;; CHECK-NEXT: (type $8 (sub (struct (field i32))))
17-
;; CHECK-NEXT: (type $9 (shared (describes $7) (descriptor $11) (struct (field (mut i64)) (field (ref $5)))))
18-
;; CHECK-NEXT: (type $10 (sub (func (param (ref $11) f32 (ref null $1) v128) (result f32))))
19-
;; CHECK-NEXT: (type $11 (shared (describes $9) (struct (field (mut v128)))))
20-
;; CHECK-NEXT: (type $12 (sub (descriptor $13) (struct (field i32) (field (mut (ref null $10))) (field i64) (field i32) (field (mut anyref)))))
21-
;; CHECK-NEXT: (type $13 (sub (describes $12) (struct (field externref) (field (ref $10)) (field (mut i32)) (field (mut i16)) (field (mut (ref null $1))) (field i8))))
22-
;; CHECK-NEXT: (type $14 (sub $8 (struct (field i32))))
13+
;; CHECK-NEXT: (type $5 (shared (descriptor $6) (struct (field f64) (field (ref $7)) (field (mut f64)) (field (mut (ref null (shared eq)))) (field (ref $11)) (field (ref (shared any))))))
14+
;; CHECK-NEXT: (type $6 (shared (describes $5) (descriptor $7) (struct (field (mut i32)) (field (mut i16)) (field i64) (field f32) (field (ref null $11)) (field (mut f64)))))
15+
;; CHECK-NEXT: (type $7 (shared (describes $6) (descriptor $9) (struct (field i8) (field (mut f32)) (field (mut f64)) (field (mut i32)) (field (mut f32)) (field (mut i64)))))
16+
;; CHECK-NEXT: (type $8 (sub (struct)))
17+
;; CHECK-NEXT: (type $9 (shared (describes $7) (descriptor $11) (struct (field (mut v128)) (field (mut v128)) (field (mut f32)))))
18+
;; CHECK-NEXT: (type $10 (func (param f32 f64 f32)))
19+
;; CHECK-NEXT: (type $11 (shared (describes $9) (struct (field (ref (shared struct))) (field i32) (field f32) (field (mut (ref null (shared struct)))) (field i64) (field i32))))
20+
;; CHECK-NEXT: (type $12 (sub (descriptor $13) (struct (field (mut i8)) (field f32) (field (mut v128)))))
21+
;; CHECK-NEXT: (type $13 (sub (describes $12) (struct (field i32) (field (ref $10)) (field i8) (field (mut i64)))))
22+
;; CHECK-NEXT: (type $14 (sub $8 (struct)))
2323
;; CHECK-NEXT: )
2424
;; CHECK-NEXT: (rec
25-
;; CHECK-NEXT: (type $15 (sub final $8 (struct (field i32) (field f64))))
26-
;; CHECK-NEXT: (type $16 (shared (func (param (ref $5) v128 (ref null $3) i64 i32 (ref any) (ref null $2)) (result (ref null $5) i32))))
27-
;; CHECK-NEXT: (type $17 (sub final $12 (descriptor $18) (struct (field i32) (field (mut (ref null $10))) (field i64) (field i32) (field (mut anyref)))))
28-
;; CHECK-NEXT: (type $18 (sub final $13 (describes $17) (struct (field (ref noextern)) (field (ref $10)) (field (mut i32)) (field (mut i16)) (field (mut (ref null $1))) (field i8))))
29-
;; CHECK-NEXT: (type $19 (sub $8 (struct (field i32) (field (mut i8)))))
25+
;; CHECK-NEXT: (type $15 (sub $8 (struct (field v128) (field (mut (ref null (shared struct)))))))
26+
;; CHECK-NEXT: (type $16 (shared (func (param (ref null $10)) (result (ref $6) i32 f64))))
27+
;; CHECK-NEXT: (type $17 (sub final $12 (descriptor $18) (struct (field (mut i8)) (field f32) (field (mut v128)) (field (ref $17)) (field (mut i8)) (field (mut eqref)))))
28+
;; CHECK-NEXT: (type $18 (sub final $13 (describes $17) (struct (field i32) (field (ref $10)) (field i8) (field (mut i64)) (field (mut (ref null $11))) (field f64))))
29+
;; CHECK-NEXT: (type $19 (sub $8 (struct (field (mut i8)) (field (mut v128)) (field v128) (field v128))))
3030
;; CHECK-NEXT: )
3131
;; CHECK-EMPTY:
3232
;; CHECK-NEXT: Inhabitable types:
@@ -35,26 +35,26 @@
3535
;; CHECK-NEXT: (rec
3636
;; CHECK-NEXT: (type $0 (sub (shared (func (param i64 f64 exnref (ref null $0)) (result (ref cont))))))
3737
;; CHECK-NEXT: (type $1 (shared (descriptor $2) (struct)))
38-
;; CHECK-NEXT: (type $2 (shared (describes $1) (descriptor $4) (struct)))
39-
;; CHECK-NEXT: (type $3 (sub (array (mut (ref null $0)))))
40-
;; CHECK-NEXT: (type $4 (sub (shared (describes $2) (struct (field (mut i8)) (field (ref null $1)) (field (mut v128)) (field (mut (ref (shared any))))))))
38+
;; CHECK-NEXT: (type $2 (shared (describes $1) (descriptor $4) (struct (field (mut v128)) (field (mut (ref $4))) (field (mut v128)) (field (mut i32)) (field f32))))
39+
;; CHECK-NEXT: (type $3 (array i8))
40+
;; CHECK-NEXT: (type $4 (shared (describes $2) (struct)))
4141
;; CHECK-NEXT: )
4242
;; CHECK-NEXT: (rec
43-
;; CHECK-NEXT: (type $5 (shared (descriptor $6) (struct)))
44-
;; CHECK-NEXT: (type $6 (sub (shared (describes $5) (descriptor $7) (struct (field (mut i8)) (field (mut i32)) (field (mut i64))))))
45-
;; CHECK-NEXT: (type $7 (sub (shared (describes $6) (descriptor $9) (struct (field (mut i64)) (field f32) (field i16) (field (mut f32))))))
46-
;; CHECK-NEXT: (type $8 (sub (struct (field i32))))
47-
;; CHECK-NEXT: (type $9 (shared (describes $7) (descriptor $11) (struct (field (mut i64)) (field (ref null $5)))))
48-
;; CHECK-NEXT: (type $10 (sub (func (param (ref $11) f32 (ref null $1) v128) (result f32))))
49-
;; CHECK-NEXT: (type $11 (shared (describes $9) (struct (field (mut v128)))))
50-
;; CHECK-NEXT: (type $12 (sub (descriptor $13) (struct (field i32) (field (mut (ref null $10))) (field i64) (field i32) (field (mut anyref)))))
51-
;; CHECK-NEXT: (type $13 (sub (describes $12) (struct (field externref) (field (ref $10)) (field (mut i32)) (field (mut i16)) (field (mut (ref null $1))) (field i8))))
52-
;; CHECK-NEXT: (type $14 (sub $8 (struct (field i32))))
43+
;; CHECK-NEXT: (type $5 (shared (descriptor $6) (struct (field f64) (field (ref $7)) (field (mut f64)) (field (mut (ref null (shared eq)))) (field (ref $11)) (field (ref (shared any))))))
44+
;; CHECK-NEXT: (type $6 (shared (describes $5) (descriptor $7) (struct (field (mut i32)) (field (mut i16)) (field i64) (field f32) (field (ref null $11)) (field (mut f64)))))
45+
;; CHECK-NEXT: (type $7 (shared (describes $6) (descriptor $9) (struct (field i8) (field (mut f32)) (field (mut f64)) (field (mut i32)) (field (mut f32)) (field (mut i64)))))
46+
;; CHECK-NEXT: (type $8 (sub (struct)))
47+
;; CHECK-NEXT: (type $9 (shared (describes $7) (descriptor $11) (struct (field (mut v128)) (field (mut v128)) (field (mut f32)))))
48+
;; CHECK-NEXT: (type $10 (func (param f32 f64 f32)))
49+
;; CHECK-NEXT: (type $11 (shared (describes $9) (struct (field (ref (shared struct))) (field i32) (field f32) (field (mut (ref null (shared struct)))) (field i64) (field i32))))
50+
;; CHECK-NEXT: (type $12 (sub (descriptor $13) (struct (field (mut i8)) (field f32) (field (mut v128)))))
51+
;; CHECK-NEXT: (type $13 (sub (describes $12) (struct (field i32) (field (ref $10)) (field i8) (field (mut i64)))))
52+
;; CHECK-NEXT: (type $14 (sub $8 (struct)))
5353
;; CHECK-NEXT: )
5454
;; CHECK-NEXT: (rec
55-
;; CHECK-NEXT: (type $15 (sub final $8 (struct (field i32) (field f64))))
56-
;; CHECK-NEXT: (type $16 (shared (func (param (ref $5) v128 (ref null $3) i64 i32 (ref any) (ref null $2)) (result (ref null $5) i32))))
57-
;; CHECK-NEXT: (type $17 (sub final $12 (descriptor $18) (struct (field i32) (field (mut (ref null $10))) (field i64) (field i32) (field (mut anyref)))))
58-
;; CHECK-NEXT: (type $18 (sub final $13 (describes $17) (struct (field nullexternref) (field (ref $10)) (field (mut i32)) (field (mut i16)) (field (mut (ref null $1))) (field i8))))
59-
;; CHECK-NEXT: (type $19 (sub $8 (struct (field i32) (field (mut i8)))))
55+
;; CHECK-NEXT: (type $15 (sub $8 (struct (field v128) (field (mut (ref null (shared struct)))))))
56+
;; CHECK-NEXT: (type $16 (shared (func (param (ref null $10)) (result (ref $6) i32 f64))))
57+
;; CHECK-NEXT: (type $17 (sub final $12 (descriptor $18) (struct (field (mut i8)) (field f32) (field (mut v128)) (field (ref null $17)) (field (mut i8)) (field (mut eqref)))))
58+
;; CHECK-NEXT: (type $18 (sub final $13 (describes $17) (struct (field i32) (field (ref $10)) (field i8) (field (mut i64)) (field (mut (ref null $11))) (field f64))))
59+
;; CHECK-NEXT: (type $19 (sub $8 (struct (field (mut i8)) (field (mut v128)) (field v128) (field v128))))
6060
;; CHECK-NEXT: )

test/lit/passes/abstract-type-refining-desc.wast

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,9 +1031,9 @@
10311031
;; NO_TNH: (rec
10321032
;; NO_TNH-NEXT: (type $A (sub (descriptor $B) (struct)))
10331033
(type $A (sub (descriptor $B) (struct)))
1034-
;; YESTNH: (type $B (describes $A) (struct))
1035-
;; NO_TNH: (type $B (describes $A) (struct))
1036-
(type $B (describes $A) (struct))
1034+
;; YESTNH: (type $B (sub (describes $A) (struct)))
1035+
;; NO_TNH: (type $B (sub (describes $A) (struct)))
1036+
(type $B (sub (describes $A) (struct)))
10371037
)
10381038

10391039
;; YESTNH: (type $2 (func (result (ref none))))

test/lit/passes/heap2local-desc.wast

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -870,8 +870,8 @@
870870
;; CHECK: (rec
871871
;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct)))
872872
(type $struct (sub (descriptor $desc) (struct)))
873-
;; CHECK: (type $desc (describes $struct) (struct))
874-
(type $desc (describes $struct) (struct))
873+
;; CHECK: (type $desc (sub (describes $struct) (struct)))
874+
(type $desc (sub (describes $struct) (struct)))
875875
)
876876

877877
;; CHECK: (type $2 (func (result (ref (exact $desc)))))
@@ -1016,7 +1016,7 @@
10161016
(module
10171017
(rec
10181018
(type $A (descriptor $B) (struct))
1019-
(type $B (sub (describes $A) (struct)))
1019+
(type $B (describes $A) (struct))
10201020
)
10211021
;; CHECK: (type $0 (func))
10221022

@@ -1156,8 +1156,8 @@
11561156
(module
11571157
(rec
11581158
;; CHECK: (rec
1159-
;; CHECK-NEXT: (type $A (shared (descriptor $B) (struct)))
1160-
(type $A (shared (descriptor $B) (struct)))
1159+
;; CHECK-NEXT: (type $A (sub (shared (descriptor $B) (struct))))
1160+
(type $A (sub (shared (descriptor $B) (struct))))
11611161
;; CHECK: (type $B (sub (shared (describes $A) (descriptor $C) (struct))))
11621162
(type $B (sub (shared (describes $A) (descriptor $C) (struct))))
11631163
;; CHECK: (type $C (sub (shared (describes $B) (struct))))
@@ -1229,10 +1229,10 @@
12291229
(module
12301230
(rec
12311231
;; CHECK: (rec
1232-
;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct)))
1233-
(type $struct (sub (descriptor $desc) (struct)))
1232+
;; CHECK-NEXT: (type $struct (descriptor $desc) (struct))
1233+
(type $struct (descriptor $desc) (struct))
12341234
;; CHECK: (type $desc (describes $struct) (struct))
1235-
(type $desc (sub final (describes $struct) (struct)))
1235+
(type $desc (describes $struct) (struct))
12361236
)
12371237

12381238
;; CHECK: (type $2 (func (result i32)))
@@ -1293,8 +1293,8 @@
12931293
;; CHECK: (rec
12941294
;; CHECK-NEXT: (type $struct (descriptor $desc) (struct))
12951295
(type $struct (descriptor $desc) (struct))
1296-
;; CHECK: (type $desc (sub (describes $struct) (struct (field funcref))))
1297-
(type $desc (sub (describes $struct) (struct (field funcref))))
1296+
;; CHECK: (type $desc (describes $struct) (struct (field funcref)))
1297+
(type $desc (describes $struct) (struct (field funcref)))
12981298
)
12991299

13001300
;; CHECK: (type $2 (func))
@@ -1374,8 +1374,8 @@
13741374
;; CHECK: (rec
13751375
;; CHECK-NEXT: (type $struct (descriptor $desc) (struct))
13761376
(type $struct (descriptor $desc) (struct))
1377-
;; CHECK: (type $desc (sub (describes $struct) (struct)))
1378-
(type $desc (sub (describes $struct) (struct)))
1377+
;; CHECK: (type $desc (describes $struct) (struct))
1378+
(type $desc (describes $struct) (struct))
13791379
)
13801380

13811381
;; CHECK: (type $2 (func))

test/lit/passes/type-ssa-desc.wast

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
;; CHECK: (rec
88
;; CHECK-NEXT: (type $struct (descriptor $desc) (struct))
99
(type $struct (descriptor $desc) (struct))
10-
;; CHECK: (type $desc (sub (describes $struct) (struct (field i32))))
11-
(type $desc (sub (describes $struct) (struct (field i32))))
10+
;; CHECK: (type $desc (describes $struct) (struct (field i32)))
11+
(type $desc (describes $struct) (struct (field i32)))
1212
)
1313
;; CHECK: (type $2 (func (result (ref $desc))))
1414

@@ -27,10 +27,10 @@
2727
(module
2828
(rec
2929
;; CHECK: (rec
30-
;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct (field i32))))
31-
(type $struct (sub (descriptor $desc) (struct (field i32))))
30+
;; CHECK-NEXT: (type $struct (descriptor $desc) (struct (field i32)))
31+
(type $struct (descriptor $desc) (struct (field i32)))
3232
;; CHECK: (type $desc (describes $struct) (struct))
33-
(type $desc (sub final (describes $struct) (struct)))
33+
(type $desc (describes $struct) (struct))
3434
)
3535

3636
;; CHECK: (type $2 (func (result (ref $struct))))

0 commit comments

Comments
 (0)