Skip to content

Commit 74cbb3b

Browse files
alexcrichtonwillemneal
authored andcommitted
Split out an Enum type from the Variant type (bytecodealliance#211)
* Split out an `Enum` type from the `Variant` type This was not 100% straightforward as the lowering of an enum wants to be `the_value as i32` in the Rust-to-wasm generator, but that's not working because sometimes `the_value` has type `&T` instead of `T` which can't be cast to `i32`. This means that lowerings in Rust are now always producing a `match` statement which should optimize to the same thing but won't be as easy on the eyes. Additionally a small change was made to the C code generator that `expected<_, _>` is now represented as a struct-of-union instead of special-cased to be an `enum`. The only reason it was special cased prior was that it was accidentally interpreted as an `enum` due to the `Variant::is_enum` check (which is now removed). * Move a test
1 parent 075f816 commit 74cbb3b

File tree

30 files changed

+817
-1020
lines changed

30 files changed

+817
-1020
lines changed

crates/gen-c/src/lib.rs

Lines changed: 86 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ impl C {
165165
match ty {
166166
Type::Id(id) => match &iface.types[*id].kind {
167167
TypeDefKind::Type(t) => self.is_arg_by_pointer(iface, t),
168-
TypeDefKind::Variant(v) => !v.is_enum(),
168+
TypeDefKind::Variant(_) => true,
169+
TypeDefKind::Enum(_) => false,
169170
TypeDefKind::Flags(_) => false,
170171
TypeDefKind::Tuple(_) | TypeDefKind::Record(_) | TypeDefKind::List(_) => true,
171172
},
@@ -244,6 +245,7 @@ impl C {
244245
TypeDefKind::Type(t) => self.print_ty(iface, t),
245246
TypeDefKind::Flags(_)
246247
| TypeDefKind::Tuple(_)
248+
| TypeDefKind::Enum(_)
247249
| TypeDefKind::Record(_)
248250
| TypeDefKind::List(_)
249251
| TypeDefKind::Variant(_) => {
@@ -282,7 +284,9 @@ impl C {
282284
}
283285
match &ty.kind {
284286
TypeDefKind::Type(t) => self.print_ty_name(iface, t),
285-
TypeDefKind::Record(_) | TypeDefKind::Flags(_) => unimplemented!(),
287+
TypeDefKind::Record(_) | TypeDefKind::Flags(_) | TypeDefKind::Enum(_) => {
288+
unimplemented!()
289+
}
286290
TypeDefKind::Tuple(t) => {
287291
self.src.h("tuple");
288292
self.src.h(&t.types.len().to_string());
@@ -324,7 +328,10 @@ impl C {
324328
self.src.h("typedef ");
325329
let kind = &iface.types[ty].kind;
326330
match kind {
327-
TypeDefKind::Type(_) | TypeDefKind::Flags(_) | TypeDefKind::Record(_) => {
331+
TypeDefKind::Type(_)
332+
| TypeDefKind::Flags(_)
333+
| TypeDefKind::Record(_)
334+
| TypeDefKind::Enum(_) => {
328335
unreachable!()
329336
}
330337
TypeDefKind::Tuple(t) => {
@@ -347,25 +354,21 @@ impl C {
347354
self.src.h(" val;\n");
348355
self.src.h("}");
349356
} else if let Some((ok, err)) = v.as_expected() {
350-
if ok.is_none() && err.is_none() {
351-
self.src.h("uint8_t");
352-
} else {
353-
self.src.h("struct {
354-
// 0 if `val` is `ok`, 1 otherwise
355-
uint8_t tag;
356-
union {
357-
");
358-
if let Some(ok) = ok {
359-
self.print_ty(iface, ok);
360-
self.src.h(" ok;\n");
361-
}
362-
if let Some(err) = err {
363-
self.print_ty(iface, err);
364-
self.src.h(" err;\n");
365-
}
366-
self.src.h("} val;\n");
367-
self.src.h("}");
357+
self.src.h("struct {
358+
// 0 if `val` is `ok`, 1 otherwise
359+
uint8_t tag;
360+
union {
361+
");
362+
if let Some(ok) = ok {
363+
self.print_ty(iface, ok);
364+
self.src.h(" ok;\n");
365+
}
366+
if let Some(err) = err {
367+
self.print_ty(iface, err);
368+
self.src.h(" err;\n");
368369
}
370+
self.src.h("} val;\n");
371+
self.src.h("}");
369372
} else {
370373
unimplemented!();
371374
}
@@ -453,6 +456,7 @@ impl C {
453456
TypeDefKind::Type(t) => self.free(iface, t, "ptr"),
454457

455458
TypeDefKind::Flags(_) => {}
459+
TypeDefKind::Enum(_) => {}
456460

457461
TypeDefKind::Record(r) => {
458462
for field in r.fields.iter() {
@@ -527,6 +531,7 @@ impl C {
527531
TypeDefKind::Record(r) => r.fields.iter().any(|t| self.owns_anything(iface, &t.ty)),
528532
TypeDefKind::Tuple(t) => t.types.iter().any(|t| self.owns_anything(iface, t)),
529533
TypeDefKind::Flags(_) => false,
534+
TypeDefKind::Enum(_) => false,
530535
TypeDefKind::List(_) => true,
531536
TypeDefKind::Variant(v) => v
532537
.cases
@@ -597,8 +602,8 @@ impl Return {
597602
// other records/lists/buffers always go to return pointers
598603
TypeDefKind::List(_) => self.retptrs.push(*orig_ty),
599604

600-
// Enums are scalars (this includes bools)
601-
TypeDefKind::Variant(v) if v.is_enum() => {
605+
// Enums are scalars
606+
TypeDefKind::Enum(_) => {
602607
self.scalar = Some(Scalar::Type(*orig_ty));
603608
}
604609

@@ -617,17 +622,15 @@ impl Return {
617622
// returned through the normal returns.
618623
if let Some((ok, err)) = r.as_expected() {
619624
if let Some(Type::Id(err)) = err {
620-
if let TypeDefKind::Variant(e) = &iface.types[*err].kind {
621-
if e.is_enum() {
622-
self.scalar = Some(Scalar::ExpectedEnum {
623-
err: *err,
624-
max_err: e.cases.len(),
625-
});
626-
if let Some(ok) = ok {
627-
self.splat_tuples(iface, ok, ok);
628-
}
629-
return;
625+
if let TypeDefKind::Enum(e) = &iface.types[*err].kind {
626+
self.scalar = Some(Scalar::ExpectedEnum {
627+
err: *err,
628+
max_err: e.cases.len(),
629+
});
630+
if let Some(ok) = ok {
631+
self.splat_tuples(iface, ok, ok);
630632
}
633+
return;
631634
}
632635
}
633636
}
@@ -760,40 +763,31 @@ impl Generator for C {
760763
let prev = mem::take(&mut self.src.header);
761764
self.docs(docs);
762765
self.names.insert(&name.to_snake_case()).unwrap();
763-
if variant.is_enum() {
764-
self.src.h("typedef ");
765-
self.src.h(int_repr(variant.tag));
766-
self.src.h(" ");
767-
self.print_namespace(iface);
768-
self.src.h(&name.to_snake_case());
769-
self.src.h("_t;\n");
770-
} else {
771-
self.src.h("typedef struct {\n");
772-
self.src.h(int_repr(variant.tag));
773-
self.src.h(" tag;\n");
774-
match variant.as_option() {
775-
Some(ty) => {
776-
self.print_ty(iface, ty);
777-
self.src.h(" val;\n");
778-
}
779-
None => {
780-
self.src.h("union {\n");
781-
for case in variant.cases.iter() {
782-
if let Some(ty) = &case.ty {
783-
self.print_ty(iface, ty);
784-
self.src.h(" ");
785-
self.src.h(&case_field_name(case));
786-
self.src.h(";\n");
787-
}
766+
self.src.h("typedef struct {\n");
767+
self.src.h(int_repr(variant.tag));
768+
self.src.h(" tag;\n");
769+
match variant.as_option() {
770+
Some(ty) => {
771+
self.print_ty(iface, ty);
772+
self.src.h(" val;\n");
773+
}
774+
None => {
775+
self.src.h("union {\n");
776+
for case in variant.cases.iter() {
777+
if let Some(ty) = &case.ty {
778+
self.print_ty(iface, ty);
779+
self.src.h(" ");
780+
self.src.h(&case_field_name(case));
781+
self.src.h(";\n");
788782
}
789-
self.src.h("} val;\n");
790783
}
784+
self.src.h("} val;\n");
791785
}
792-
self.src.h("} ");
793-
self.print_namespace(iface);
794-
self.src.h(&name.to_snake_case());
795-
self.src.h("_t;\n");
796786
}
787+
self.src.h("} ");
788+
self.print_namespace(iface);
789+
self.src.h(&name.to_snake_case());
790+
self.src.h("_t;\n");
797791
for (i, case) in variant.cases.iter().enumerate() {
798792
self.src.h(&format!(
799793
"#define {}_{}_{} {}\n",
@@ -808,6 +802,30 @@ impl Generator for C {
808802
.insert(id, mem::replace(&mut self.src.header, prev));
809803
}
810804

805+
fn type_enum(&mut self, iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
806+
let prev = mem::take(&mut self.src.header);
807+
self.docs(docs);
808+
self.names.insert(&name.to_snake_case()).unwrap();
809+
self.src.h("typedef ");
810+
self.src.h(int_repr(enum_.tag()));
811+
self.src.h(" ");
812+
self.print_namespace(iface);
813+
self.src.h(&name.to_snake_case());
814+
self.src.h("_t;\n");
815+
for (i, case) in enum_.cases.iter().enumerate() {
816+
self.src.h(&format!(
817+
"#define {}_{}_{} {}\n",
818+
iface.name.to_shouty_snake_case(),
819+
name.to_shouty_snake_case(),
820+
case.name.to_shouty_snake_case(),
821+
i,
822+
));
823+
}
824+
825+
self.types
826+
.insert(id, mem::replace(&mut self.src.header, prev));
827+
}
828+
811829
fn type_resource(&mut self, iface: &Interface, ty: ResourceId) {
812830
drop((iface, ty));
813831
}
@@ -1477,6 +1495,7 @@ impl Bindgen for FunctionBindgen<'_> {
14771495
results.push(format!("*{}", name));
14781496
self.payloads.push(name);
14791497
}
1498+
14801499
Instruction::VariantLower {
14811500
variant,
14821501
results: result_types,
@@ -1491,11 +1510,6 @@ impl Bindgen for FunctionBindgen<'_> {
14911510
.drain(self.payloads.len() - variant.cases.len()..)
14921511
.collect::<Vec<_>>();
14931512

1494-
if results.len() == 1 && variant.is_enum() {
1495-
results.push(format!("(int32_t) {}", operands[0]));
1496-
return;
1497-
}
1498-
14991513
let mut variant_results = Vec::new();
15001514
for ty in result_types.iter() {
15011515
let name = self.locals.tmp("variant");
@@ -1507,11 +1521,7 @@ impl Bindgen for FunctionBindgen<'_> {
15071521
variant_results.push(name);
15081522
}
15091523

1510-
let expr_to_match = if variant.is_enum() {
1511-
operands[0].to_string()
1512-
} else {
1513-
format!("({}).tag", operands[0])
1514-
};
1524+
let expr_to_match = format!("({}).tag", operands[0]);
15151525

15161526
self.src
15171527
.push_str(&format!("switch ((int32_t) {}) {{\n", expr_to_match));
@@ -1549,10 +1559,6 @@ impl Bindgen for FunctionBindgen<'_> {
15491559
.drain(self.blocks.len() - variant.cases.len()..)
15501560
.collect::<Vec<_>>();
15511561

1552-
if variant.is_enum() {
1553-
return results.push(operands.pop().unwrap());
1554-
}
1555-
15561562
let ty = self.gen.type_string(iface, &Type::Id(*ty));
15571563
let result = self.locals.tmp("variant");
15581564
self.src.push_str(&format!("{} {};\n", ty, result));
@@ -1583,6 +1589,9 @@ impl Bindgen for FunctionBindgen<'_> {
15831589
results.push(result);
15841590
}
15851591

1592+
Instruction::EnumLower { .. } => results.push(format!("(int32_t) {}", operands[0])),
1593+
Instruction::EnumLift { .. } => results.push(operands.pop().unwrap()),
1594+
15861595
Instruction::ListCanonLower { .. } | Instruction::StringLower { .. } => {
15871596
results.push(format!("(int32_t) ({}).ptr", operands[0]));
15881597
results.push(format!("(int32_t) ({}).len", operands[0]));

crates/gen-core/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub trait Generator {
6565
variant: &Variant,
6666
docs: &Docs,
6767
);
68+
fn type_enum(&mut self, iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs);
6869
fn type_resource(&mut self, iface: &Interface, ty: ResourceId);
6970
fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
7071
fn type_list(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs);
@@ -92,6 +93,7 @@ pub trait Generator {
9293
TypeDefKind::Record(record) => self.type_record(iface, id, name, record, &ty.docs),
9394
TypeDefKind::Flags(flags) => self.type_flags(iface, id, name, flags, &ty.docs),
9495
TypeDefKind::Tuple(tuple) => self.type_tuple(iface, id, name, tuple, &ty.docs),
96+
TypeDefKind::Enum(enum_) => self.type_enum(iface, id, name, enum_, &ty.docs),
9597
TypeDefKind::Variant(variant) => {
9698
self.type_variant(iface, id, name, variant, &ty.docs)
9799
}
@@ -198,6 +200,7 @@ impl Types {
198200
}
199201
}
200202
TypeDefKind::Flags(_) => {}
203+
TypeDefKind::Enum(_) => {}
201204
TypeDefKind::Variant(v) => {
202205
for case in v.cases.iter() {
203206
if let Some(ty) = &case.ty {
@@ -241,6 +244,7 @@ impl Types {
241244
}
242245
}
243246
TypeDefKind::Flags(_) => {}
247+
TypeDefKind::Enum(_) => {}
244248
TypeDefKind::Variant(v) => {
245249
for case in v.cases.iter() {
246250
if let Some(ty) = &case.ty {

0 commit comments

Comments
 (0)