Skip to content

Commit 18c1c95

Browse files
authored
wasmparser(CM+GC): Add support for lowering variants, options, and results to GC types (#2217)
* wasmparser(CM+GC): Add support for lowering variants, options, and results to GC types This completes prototype support for GC in the component model by filling out the lowering of sum types (variants, options, and results) to GC types. * Remove discriminants from sum types As per WebAssembly/component-model#525 (comment)
1 parent a523f31 commit 18c1c95

File tree

19 files changed

+637
-6
lines changed

19 files changed

+637
-6
lines changed

crates/wasmparser/src/validator/component_types.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,7 @@ pub struct RecordType {
13411341
/// The map of record fields.
13421342
pub fields: IndexMap<KebabString, ComponentValType>,
13431343
}
1344+
13441345
impl RecordType {
13451346
fn lower_gc(
13461347
&self,
@@ -1370,6 +1371,7 @@ pub struct VariantType {
13701371
/// The map of variant cases.
13711372
pub cases: IndexMap<KebabString, VariantCase>,
13721373
}
1374+
13731375
impl VariantType {
13741376
fn lower_gc(
13751377
&self,
@@ -1378,12 +1380,36 @@ impl VariantType {
13781380
options: &CanonicalOptions,
13791381
offset: usize,
13801382
core: ArgOrField,
1381-
) -> core::result::Result<(), BinaryReaderError> {
1382-
let _ = (types, abi, options, offset, core);
1383-
todo!("variant types and CM+GC")
1383+
) -> Result<()> {
1384+
lower_gc_sum_type(types, abi, options, offset, core, "variant")
13841385
}
13851386
}
13861387

1388+
/// Common helper for lowering sum types (variants, options, and results) to
1389+
/// core GC types.
1390+
fn lower_gc_sum_type(
1391+
types: &TypeList,
1392+
_abi: Abi,
1393+
_options: &CanonicalOptions,
1394+
offset: usize,
1395+
core: ArgOrField,
1396+
kind: &str,
1397+
) -> Result<()> {
1398+
if let Some(id) = core.as_concrete_ref() {
1399+
if let CompositeInnerType::Struct(ty) = &types[id].composite_type.inner {
1400+
if ty.fields.is_empty() {
1401+
return Ok(());
1402+
}
1403+
}
1404+
}
1405+
1406+
bail!(
1407+
offset,
1408+
"expected to lower component `{kind}` type to core `(ref null? (struct))`, \
1409+
but found `{core}`",
1410+
)
1411+
}
1412+
13871413
/// Represents a tuple type.
13881414
#[derive(Debug, Clone)]
13891415
pub struct TupleType {
@@ -1392,6 +1418,7 @@ pub struct TupleType {
13921418
/// The types of the tuple.
13931419
pub types: Box<[ComponentValType]>,
13941420
}
1421+
13951422
impl TupleType {
13961423
fn lower_gc(
13971424
&self,
@@ -1400,7 +1427,7 @@ impl TupleType {
14001427
options: &CanonicalOptions,
14011428
offset: usize,
14021429
core: ArgOrField,
1403-
) -> core::result::Result<(), BinaryReaderError> {
1430+
) -> Result<()> {
14041431
lower_gc_product_type(
14051432
self.types.iter(),
14061433
types,
@@ -1666,9 +1693,13 @@ impl ComponentDefinedType {
16661693
}
16671694
}
16681695

1669-
ComponentDefinedType::Option(_) => todo!("option types and CM+GC"),
1696+
ComponentDefinedType::Option(_) => {
1697+
lower_gc_sum_type(types, abi, options, offset, core, "option")
1698+
}
16701699

1671-
ComponentDefinedType::Result { .. } => todo!("result types and CM+GC"),
1700+
ComponentDefinedType::Result { .. } => {
1701+
lower_gc_sum_type(types, abi, options, offset, core, "result")
1702+
}
16721703

16731704
ComponentDefinedType::Own(_)
16741705
| ComponentDefinedType::Borrow(_)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
;; RUN: wast --assert default --snapshot tests/snapshots % -f gc,cm-gc
2+
3+
;; Basic.
4+
(component
5+
(type $opt (option u32))
6+
7+
(core type $opt (struct))
8+
(core type $ty (func (param (ref $opt))))
9+
10+
(import "i" (instance $i
11+
(export "ty" (type $opt' (eq $opt)))
12+
(export "f" (func (param "x" $opt')))))
13+
(core func (canon lower (func $i "f") gc (core-type $ty)))
14+
)
15+
16+
;; With a nullable reference.
17+
(component
18+
(type $opt (option u32))
19+
20+
(core type $opt (struct))
21+
(core type $ty (func (param (ref null $opt))))
22+
23+
(import "i" (instance $i
24+
(export "ty" (type $opt' (eq $opt)))
25+
(export "f" (func (param "x" $opt')))))
26+
(core func (canon lower (func $i "f") gc (core-type $ty)))
27+
)
28+
29+
;; With a custom rec group.
30+
(component
31+
(type $opt (option u32))
32+
33+
(core rec
34+
(type $opt (struct))
35+
(type $ty (func (param (ref $opt)))))
36+
37+
(import "i" (instance $i
38+
(export "ty" (type $opt' (eq $opt)))
39+
(export "f" (func (param "x" $opt')))))
40+
(core func (canon lower (func $i "f") gc (core-type $ty)))
41+
)
42+
43+
;; With a custom subtype.
44+
(component
45+
(type $opt (option u32))
46+
47+
(core type $base (sub (struct)))
48+
(core type $opt (sub $base (struct)))
49+
(core type $ty (func (param (ref $opt))))
50+
51+
(import "i" (instance $i
52+
(export "ty" (type $opt' (eq $opt)))
53+
(export "f" (func (param "x" $opt')))))
54+
(core func (canon lower (func $i "f") gc (core-type $ty)))
55+
)
56+
57+
;; Unexpected field.
58+
(assert_invalid
59+
(component
60+
(type $opt (option u32))
61+
62+
(core type $opt (struct (field i32)))
63+
(core type $ty (func (param (ref $opt))))
64+
65+
(import "i" (instance $i
66+
(export "ty" (type $opt' (eq $opt)))
67+
(export "f" (func (param "x" $opt')))))
68+
(core func (canon lower (func $i "f") gc (core-type $ty)))
69+
)
70+
"expected to lower component `option` type to core `(ref null? (struct))`"
71+
)
72+
73+
;; Lowering into a non-struct.
74+
(assert_invalid
75+
(component
76+
(type $opt (option u32))
77+
78+
(core type $ty (func (param externref)))
79+
80+
(import "i" (instance $i
81+
(export "ty" (type $opt' (eq $opt)))
82+
(export "f" (func (param "x" $opt')))))
83+
(core func (canon lower (func $i "f") gc (core-type $ty)))
84+
)
85+
"expected to lower component `option` type to core `(ref null? (struct))`"
86+
)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
;; RUN: wast --assert default --snapshot tests/snapshots % -f gc,cm-gc
2+
3+
;; Basic.
4+
(component
5+
(type $result (result u32 (error u8)))
6+
7+
(core type $result (struct))
8+
(core type $ty (func (param (ref $result))))
9+
10+
(import "i" (instance $i
11+
(export "ty" (type $result' (eq $result)))
12+
(export "f" (func (param "x" $result')))))
13+
(core func (canon lower (func $i "f") gc (core-type $ty)))
14+
)
15+
16+
;; With a nullable reference.
17+
(component
18+
(type $result (result u32 (error u8)))
19+
20+
(core type $result (struct))
21+
(core type $ty (func (param (ref null $result))))
22+
23+
(import "i" (instance $i
24+
(export "ty" (type $result' (eq $result)))
25+
(export "f" (func (param "x" $result')))))
26+
(core func (canon lower (func $i "f") gc (core-type $ty)))
27+
)
28+
29+
;; With a custom rec group.
30+
(component
31+
(type $result (result u32 (error u8)))
32+
33+
(core rec
34+
(type $result (struct))
35+
(type $ty (func (param (ref null $result)))))
36+
37+
(import "i" (instance $i
38+
(export "ty" (type $result' (eq $result)))
39+
(export "f" (func (param "x" $result')))))
40+
(core func (canon lower (func $i "f") gc (core-type $ty)))
41+
)
42+
43+
;; With a custom subtype.
44+
(component
45+
(type $result (result u32 (error u8)))
46+
47+
(core type $base (sub (struct)))
48+
(core type $result (sub $base (struct)))
49+
(core type $ty (func (param (ref null $result))))
50+
51+
(import "i" (instance $i
52+
(export "ty" (type $result' (eq $result)))
53+
(export "f" (func (param "x" $result')))))
54+
(core func (canon lower (func $i "f") gc (core-type $ty)))
55+
)
56+
57+
;; Unexpected fields in struct type.
58+
(assert_invalid
59+
(component
60+
(type $result (result u32 (error u8)))
61+
62+
(core type $result (struct (field i8) (field i8)))
63+
(core type $ty (func (param (ref $result))))
64+
65+
(import "i" (instance $i
66+
(export "ty" (type $result' (eq $result)))
67+
(export "f" (func (param "x" $result')))))
68+
(core func (canon lower (func $i "f") gc (core-type $ty)))
69+
)
70+
"expected to lower component `result` type to core `(ref null? (struct))`"
71+
)
72+
73+
;; Lowering into a non-struct.
74+
(assert_invalid
75+
(component
76+
(type $result (result u32 (error u8)))
77+
78+
(core type $ty (func (param externref)))
79+
80+
(import "i" (instance $i
81+
(export "ty" (type $result' (eq $result)))
82+
(export "f" (func (param "x" $result')))))
83+
(core func (canon lower (func $i "f") gc (core-type $ty)))
84+
)
85+
"expected to lower component `result` type to core `(ref null? (struct))`"
86+
)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
;; RUN: wast --assert default --snapshot tests/snapshots % -f gc,cm-gc
2+
3+
;; Basic.
4+
(component
5+
(type $variant (variant (case "a" bool)
6+
(case "b" bool)
7+
(case "c" u8)))
8+
9+
(core type $variant (struct))
10+
(core type $ty (func (param (ref $variant))))
11+
12+
(import "i" (instance $i
13+
(export "ty" (type $variant' (eq $variant)))
14+
(export "f" (func (param "x" $variant')))))
15+
(core func (canon lower (func $i "f") gc (core-type $ty)))
16+
)
17+
18+
;; With a nullable reference.
19+
(component
20+
(type $variant (variant (case "a" bool)
21+
(case "b" bool)
22+
(case "c" u8)))
23+
24+
(core type $variant (struct))
25+
(core type $ty (func (param (ref null $variant))))
26+
27+
(import "i" (instance $i
28+
(export "ty" (type $variant' (eq $variant)))
29+
(export "f" (func (param "x" $variant')))))
30+
(core func (canon lower (func $i "f") gc (core-type $ty)))
31+
)
32+
33+
;; With a custom rec group.
34+
(component
35+
(type $variant (variant (case "a" bool)
36+
(case "b" bool)
37+
(case "c" u8)))
38+
39+
(core rec
40+
(type $variant (struct))
41+
(type $ty (func (param (ref null $variant)))))
42+
43+
(import "i" (instance $i
44+
(export "ty" (type $variant' (eq $variant)))
45+
(export "f" (func (param "x" $variant')))))
46+
(core func (canon lower (func $i "f") gc (core-type $ty)))
47+
)
48+
49+
;; With a custom subtype.
50+
(component
51+
(type $variant (variant (case "a" bool)
52+
(case "b" bool)
53+
(case "c" u8)))
54+
55+
(core type $base (sub (struct)))
56+
(core type $variant (sub $base (struct)))
57+
(core type $ty (func (param (ref null $variant))))
58+
59+
(import "i" (instance $i
60+
(export "ty" (type $variant' (eq $variant)))
61+
(export "f" (func (param "x" $variant')))))
62+
(core func (canon lower (func $i "f") gc (core-type $ty)))
63+
)
64+
65+
;; Unexpected field in struct.
66+
(assert_invalid
67+
(component
68+
(type $variant (variant (case "a" bool)
69+
(case "b" bool)
70+
(case "c" u8)))
71+
72+
(core type $variant (struct (field i8)))
73+
(core type $ty (func (param (ref $variant))))
74+
75+
(import "i" (instance $i
76+
(export "ty" (type $variant' (eq $variant)))
77+
(export "f" (func (param "x" $variant')))))
78+
(core func (canon lower (func $i "f") gc (core-type $ty)))
79+
)
80+
"expected to lower component `variant` type to core `(ref null? (struct))`"
81+
)
82+
83+
;; Lowering into a non-struct.
84+
(assert_invalid
85+
(component
86+
(type $variant (variant (case "a" bool)
87+
(case "b" bool)
88+
(case "c" u8)))
89+
90+
(core type $ty (func (param externref)))
91+
92+
(import "i" (instance $i
93+
(export "ty" (type $variant' (eq $variant)))
94+
(export "f" (func (param "x" $variant')))))
95+
(core func (canon lower (func $i "f") gc (core-type $ty)))
96+
)
97+
"expected to lower component `variant` type to core `(ref null? (struct))`"
98+
)

0 commit comments

Comments
 (0)