Skip to content

Commit 39db35a

Browse files
authored
Split out a Union type from Variant (#219)
* Split out a `Union` type from `Variant` This commit splits out the union specialization from `variant`, finalizing the transition to the new AST of types available in the current component model draft. This is mostly like the prior splittings-out where there's some duplication but it's relatively localized and hopefully not too hard to follow. * Fill out TODO
1 parent 51af112 commit 39db35a

File tree

29 files changed

+1007
-342
lines changed

29 files changed

+1007
-342
lines changed

crates/gen-c/src/lib.rs

Lines changed: 130 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ impl C {
166166
Type::Id(id) => match &iface.types[*id].kind {
167167
TypeDefKind::Type(t) => self.is_arg_by_pointer(iface, t),
168168
TypeDefKind::Variant(_) => true,
169+
TypeDefKind::Union(_) => true,
169170
TypeDefKind::Option(_) => true,
170171
TypeDefKind::Expected(_) => true,
171172
TypeDefKind::Enum(_) => false,
@@ -285,7 +286,8 @@ impl C {
285286
TypeDefKind::Record(_)
286287
| TypeDefKind::Flags(_)
287288
| TypeDefKind::Enum(_)
288-
| TypeDefKind::Variant(_) => {
289+
| TypeDefKind::Variant(_)
290+
| TypeDefKind::Union(_) => {
289291
unimplemented!()
290292
}
291293
TypeDefKind::Tuple(t) => {
@@ -324,7 +326,8 @@ impl C {
324326
| TypeDefKind::Flags(_)
325327
| TypeDefKind::Record(_)
326328
| TypeDefKind::Enum(_)
327-
| TypeDefKind::Variant(_) => {
329+
| TypeDefKind::Variant(_)
330+
| TypeDefKind::Union(_) => {
328331
unreachable!()
329332
}
330333
TypeDefKind::Tuple(t) => {
@@ -493,14 +496,29 @@ impl C {
493496
continue;
494497
}
495498
self.src.c(&format!("case {}: {{\n", i));
496-
let expr = format!("&ptr->val.{}", case_field_name(case));
499+
let expr = format!("&ptr->val.{}", case.name.to_snake_case());
497500
self.free(iface, case_ty, &expr);
498501
self.src.c("break;\n");
499502
self.src.c("}\n");
500503
}
501504
self.src.c("}\n");
502505
}
503506

507+
TypeDefKind::Union(u) => {
508+
self.src.c("switch ((int32_t) ptr->tag) {\n");
509+
for (i, case) in u.cases.iter().enumerate() {
510+
if !self.owns_anything(iface, &case.ty) {
511+
continue;
512+
}
513+
self.src.c(&format!("case {i}: {{\n"));
514+
let expr = format!("&ptr->val.f{i}");
515+
self.free(iface, &case.ty, &expr);
516+
self.src.c("break;\n");
517+
self.src.c("}\n");
518+
}
519+
self.src.c("}\n");
520+
}
521+
504522
TypeDefKind::Option(t) => {
505523
self.src.c("if (ptr->is_some) {\n");
506524
self.free(iface, t, "&ptr->val");
@@ -541,6 +559,10 @@ impl C {
541559
.iter()
542560
.filter_map(|c| c.ty.as_ref())
543561
.any(|t| self.owns_anything(iface, t)),
562+
TypeDefKind::Union(v) => v
563+
.cases
564+
.iter()
565+
.any(|case| self.owns_anything(iface, &case.ty)),
544566
TypeDefKind::Option(t) => self.owns_anything(iface, t),
545567
TypeDefKind::Expected(e) => {
546568
self.owns_anything(iface, &e.ok) || self.owns_anything(iface, &e.err)
@@ -642,7 +664,7 @@ impl Return {
642664
self.retptrs.push(*orig_ty);
643665
}
644666

645-
TypeDefKind::Variant(_) => {
667+
TypeDefKind::Variant(_) | TypeDefKind::Union(_) => {
646668
self.retptrs.push(*orig_ty);
647669
}
648670
}
@@ -778,7 +800,7 @@ impl Generator for C {
778800
if let Some(ty) = &case.ty {
779801
self.print_ty(iface, ty);
780802
self.src.h(" ");
781-
self.src.h(&case_field_name(case));
803+
self.src.h(&case.name.to_snake_case());
782804
self.src.h(";\n");
783805
}
784806
}
@@ -801,6 +823,35 @@ impl Generator for C {
801823
.insert(id, mem::replace(&mut self.src.header, prev));
802824
}
803825

826+
fn type_union(
827+
&mut self,
828+
iface: &Interface,
829+
id: TypeId,
830+
name: &str,
831+
union: &Union,
832+
docs: &Docs,
833+
) {
834+
let prev = mem::take(&mut self.src.header);
835+
self.docs(docs);
836+
self.names.insert(&name.to_snake_case()).unwrap();
837+
self.src.h("typedef struct {\n");
838+
self.src.h(int_repr(union.tag()));
839+
self.src.h(" tag;\n");
840+
self.src.h("union {\n");
841+
for (i, case) in union.cases.iter().enumerate() {
842+
self.print_ty(iface, &case.ty);
843+
self.src.h(&format!(" f{i};\n"));
844+
}
845+
self.src.h("} val;\n");
846+
self.src.h("} ");
847+
self.print_namespace(iface);
848+
self.src.h(&name.to_snake_case());
849+
self.src.h("_t;\n");
850+
851+
self.types
852+
.insert(id, mem::replace(&mut self.src.header, prev));
853+
}
854+
804855
fn type_option(
805856
&mut self,
806857
iface: &Interface,
@@ -1594,7 +1645,7 @@ impl Bindgen for FunctionBindgen<'_> {
15941645
ty, payload, operands[0],
15951646
));
15961647
self.src.push_str(".");
1597-
self.src.push_str(&case_field_name(case));
1648+
self.src.push_str(&case.name.to_snake_case());
15981649
self.src.push_str(";\n");
15991650
}
16001651
}
@@ -1631,7 +1682,7 @@ impl Bindgen for FunctionBindgen<'_> {
16311682
assert!(block_results.len() == 1);
16321683
let mut dst = format!("{}.val", result);
16331684
dst.push_str(".");
1634-
dst.push_str(&case_field_name(case));
1685+
dst.push_str(&case.name.to_snake_case());
16351686
self.store_op(&block_results[0], &dst);
16361687
} else {
16371688
assert!(block_results.is_empty());
@@ -1642,6 +1693,78 @@ impl Bindgen for FunctionBindgen<'_> {
16421693
results.push(result);
16431694
}
16441695

1696+
Instruction::UnionLower {
1697+
union,
1698+
results: result_types,
1699+
..
1700+
} => {
1701+
let blocks = self
1702+
.blocks
1703+
.drain(self.blocks.len() - union.cases.len()..)
1704+
.collect::<Vec<_>>();
1705+
let payloads = self
1706+
.payloads
1707+
.drain(self.payloads.len() - union.cases.len()..)
1708+
.collect::<Vec<_>>();
1709+
1710+
let mut union_results = Vec::with_capacity(result_types.len());
1711+
for ty in result_types.iter() {
1712+
let name = self.locals.tmp("unionres");
1713+
results.push(name.clone());
1714+
let ty = wasm_type(*ty);
1715+
self.src.push_str(&format!("{ty} {name};\n"));
1716+
union_results.push(name);
1717+
}
1718+
1719+
let op0 = &operands[0];
1720+
self.src.push_str(&format!("switch (({op0}).tag) {{\n"));
1721+
for (i, ((case, (block, block_results)), payload)) in
1722+
union.cases.iter().zip(blocks).zip(payloads).enumerate()
1723+
{
1724+
self.src.push_str(&format!("case {i}: {{\n"));
1725+
if !self.gen.is_empty_type(iface, &case.ty) {
1726+
let ty = self.gen.type_string(iface, &case.ty);
1727+
self.src
1728+
.push_str(&format!("const {ty} *{payload} = &({op0}).val.f{i};\n"));
1729+
}
1730+
self.src.push_str(&block);
1731+
1732+
for (name, result) in union_results.iter().zip(&block_results) {
1733+
self.src.push_str(&format!("{name} = {result};\n"));
1734+
}
1735+
self.src.push_str("break;\n}\n");
1736+
}
1737+
self.src.push_str("}\n");
1738+
}
1739+
1740+
Instruction::UnionLift { union, ty, .. } => {
1741+
let blocks = self
1742+
.blocks
1743+
.drain(self.blocks.len() - union.cases.len()..)
1744+
.collect::<Vec<_>>();
1745+
1746+
let ty = self.gen.type_string(iface, &Type::Id(*ty));
1747+
let result = self.locals.tmp("unionres");
1748+
self.src.push_str(&format!("{} {};\n", ty, result));
1749+
self.src
1750+
.push_str(&format!("{}.tag = {};\n", result, operands[0]));
1751+
self.src
1752+
.push_str(&format!("switch ((int32_t) {}.tag) {{\n", result));
1753+
for (i, (_case, (block, block_results))) in
1754+
union.cases.iter().zip(blocks).enumerate()
1755+
{
1756+
self.src.push_str(&format!("case {i}: {{\n"));
1757+
self.src.push_str(&block);
1758+
1759+
assert!(block_results.len() == 1);
1760+
let dst = format!("{result}.val.f{i}");
1761+
self.store_op(&block_results[0], &dst);
1762+
self.src.push_str("break;\n}\n");
1763+
}
1764+
self.src.push_str("}\n");
1765+
results.push(result);
1766+
}
1767+
16451768
Instruction::OptionLower {
16461769
results: result_types,
16471770
payload,
@@ -2110,14 +2233,6 @@ fn int_repr(ty: Int) -> &'static str {
21102233
}
21112234
}
21122235

2113-
fn case_field_name(case: &Case) -> String {
2114-
if case.name.parse::<u32>().is_ok() {
2115-
format!("f{}", case.name)
2116-
} else {
2117-
case.name.to_snake_case()
2118-
}
2119-
}
2120-
21212236
fn flags_repr(f: &Flags) -> Int {
21222237
match f.repr() {
21232238
FlagsRepr::U8 => Int::U8,

crates/gen-core/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub trait Generator {
8181
expected: &Expected,
8282
docs: &Docs,
8383
);
84+
fn type_union(&mut self, iface: &Interface, id: TypeId, name: &str, union: &Union, docs: &Docs);
8485
fn type_enum(&mut self, iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs);
8586
fn type_resource(&mut self, iface: &Interface, ty: ResourceId);
8687
fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
@@ -115,6 +116,7 @@ pub trait Generator {
115116
}
116117
TypeDefKind::Option(t) => self.type_option(iface, id, name, t, &ty.docs),
117118
TypeDefKind::Expected(e) => self.type_expected(iface, id, name, e, &ty.docs),
119+
TypeDefKind::Union(u) => self.type_union(iface, id, name, u, &ty.docs),
118120
TypeDefKind::List(t) => self.type_list(iface, id, name, t, &ty.docs),
119121
TypeDefKind::Type(t) => self.type_alias(iface, id, name, t, &ty.docs),
120122
}
@@ -240,6 +242,11 @@ impl Types {
240242
info = self.type_info(iface, &e.ok);
241243
info |= self.type_info(iface, &e.err);
242244
}
245+
TypeDefKind::Union(u) => {
246+
for case in u.cases.iter() {
247+
info |= self.type_info(iface, &case.ty);
248+
}
249+
}
243250
}
244251
self.type_info.insert(ty, info);
245252
return info;
@@ -284,6 +291,11 @@ impl Types {
284291
self.set_param_result_ty(iface, &e.ok, param, result);
285292
self.set_param_result_ty(iface, &e.err, param, result);
286293
}
294+
TypeDefKind::Union(u) => {
295+
for case in u.cases.iter() {
296+
self.set_param_result_ty(iface, &case.ty, param, result)
297+
}
298+
}
287299
}
288300
}
289301

0 commit comments

Comments
 (0)