Skip to content

Commit d7b1fde

Browse files
authored
fix: added empty checks to option and result types (#473)
* added empty checks to option and result types Signed-off-by: Jiaxiao Zhou <[email protected]> * clean up Signed-off-by: Jiaxiao Zhou <[email protected]> * cargo fmt Signed-off-by: Jiaxiao Zhou <[email protected]> --------- Signed-off-by: Jiaxiao Zhou <[email protected]>
1 parent c18a5bb commit d7b1fde

File tree

2 files changed

+169
-80
lines changed

2 files changed

+169
-80
lines changed

crates/gen-guest-c/src/lib.rs

Lines changed: 93 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct CSig {
6363
enum Scalar {
6464
Void,
6565
OptionBool(Type),
66-
ResultBool(bool),
66+
ResultBool(Option<Type>, Option<Type>),
6767
Type(Type),
6868
}
6969

@@ -448,15 +448,13 @@ impl Return {
448448
// Unpack a result as a boolean return type, with two
449449
// return pointers for ok and err values
450450
TypeDefKind::Result(r) => {
451-
let mut has_ok_type = false;
452451
if let Some(ok) = r.ok {
453-
has_ok_type = true;
454452
self.retptrs.push(ok);
455453
}
456454
if let Some(err) = r.err {
457455
self.retptrs.push(err);
458456
}
459-
self.scalar = Some(Scalar::ResultBool(has_ok_type));
457+
self.scalar = Some(Scalar::ResultBool(r.ok, r.err));
460458
return;
461459
}
462460

@@ -956,9 +954,9 @@ impl InterfaceGenerator<'_> {
956954
match &ret.scalar {
957955
None | Some(Scalar::Void) => self.src.h_fns("void"),
958956
Some(Scalar::OptionBool(_id)) => self.src.h_fns("bool"),
959-
Some(Scalar::ResultBool(has_ok_type)) => {
957+
Some(Scalar::ResultBool(ok, _err)) => {
960958
result_rets = true;
961-
result_rets_has_ok_type = *has_ok_type;
959+
result_rets_has_ok_type = ok.is_some();
962960
self.src.h_fns("bool");
963961
}
964962
Some(Scalar::Type(ty)) => self.print_ty(SourceType::HFns, ty),
@@ -1593,10 +1591,6 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
15931591
);
15941592
self.ret_store_cnt = self.ret_store_cnt + 1;
15951593
}
1596-
1597-
fn check_all_retptrs_written(&self) {
1598-
assert!(self.ret_store_cnt == self.sig.retptrs.len());
1599-
}
16001594
}
16011595

16021596
impl Bindgen for FunctionBindgen<'_, '_> {
@@ -2277,28 +2271,41 @@ impl Bindgen for FunctionBindgen<'_, '_> {
22772271
.gen
22782272
.type_string(func.results.iter_types().next().unwrap());
22792273
let option_ret = self.locals.tmp("ret");
2280-
uwrite!(
2281-
self.src,
2282-
"
2283-
{ty} {ret};
2284-
{ret}.is_some = {tag};
2285-
{ret}.val = {val};
2286-
",
2287-
ty = option_ty,
2288-
ret = option_ret,
2289-
tag = ret,
2290-
val = val,
2291-
);
2274+
if !self.gen.is_empty_type(ty) {
2275+
uwrite!(
2276+
self.src,
2277+
"
2278+
{ty} {ret};
2279+
{ret}.is_some = {tag};
2280+
{ret}.val = {val};
2281+
",
2282+
ty = option_ty,
2283+
ret = option_ret,
2284+
tag = ret,
2285+
val = val,
2286+
);
2287+
} else {
2288+
uwrite!(
2289+
self.src,
2290+
"
2291+
{ty} {ret};
2292+
{ret}.is_some = {tag};
2293+
",
2294+
ty = option_ty,
2295+
ret = option_ret,
2296+
tag = ret,
2297+
);
2298+
}
22922299
results.push(option_ret);
22932300
}
2294-
Some(Scalar::ResultBool(has_ok_type)) => {
2301+
Some(Scalar::ResultBool(ok, err)) => {
22952302
let result_ty = self
22962303
.gen
22972304
.type_string(func.results.iter_types().next().unwrap());
22982305
let ret = self.locals.tmp("ret");
22992306
let mut ret_iter = self.sig.ret.retptrs.iter();
23002307
uwriteln!(self.src, "{result_ty} {ret};");
2301-
let ok_name = if *has_ok_type {
2308+
let ok_name = if ok.is_some() {
23022309
if let Some(ty) = ret_iter.next() {
23032310
let val = self.locals.tmp("ok");
23042311
if args.len() > 0 {
@@ -2329,82 +2336,88 @@ impl Bindgen for FunctionBindgen<'_, '_> {
23292336
assert!(ret_iter.next().is_none());
23302337
uwrite!(self.src, "");
23312338
uwriteln!(self.src, "{ret}.is_err = !{}({args});", self.sig.name);
2332-
2333-
if let Some(err_name) = err_name {
2334-
uwriteln!(
2335-
self.src,
2336-
"if ({ret}.is_err) {{
2337-
{ret}.val.err = {err_name};
2338-
}}",
2339-
);
2339+
if self.gen.get_nonempty_type(err.as_ref()).is_some() {
2340+
if let Some(err_name) = err_name {
2341+
uwriteln!(
2342+
self.src,
2343+
"if ({ret}.is_err) {{
2344+
{ret}.val.err = {err_name};
2345+
}}",
2346+
);
2347+
}
23402348
}
2341-
if let Some(ok_name) = ok_name {
2342-
uwriteln!(
2343-
self.src,
2344-
"if (!{ret}.is_err) {{
2345-
{ret}.val.ok = {ok_name};
2346-
}}"
2347-
);
2348-
} else {
2349-
uwrite!(self.src, "\n");
2349+
if self.gen.get_nonempty_type(ok.as_ref()).is_some() {
2350+
if let Some(ok_name) = ok_name {
2351+
uwriteln!(
2352+
self.src,
2353+
"if (!{ret}.is_err) {{
2354+
{ret}.val.ok = {ok_name};
2355+
}}"
2356+
);
2357+
} else {
2358+
uwrite!(self.src, "\n");
2359+
}
23502360
}
23512361
results.push(ret);
23522362
}
23532363
}
23542364
}
2355-
Instruction::Return { .. } if self.gen.in_import => {
2356-
match self.sig.ret.scalar {
2357-
None => {
2358-
for op in operands.iter() {
2359-
self.store_in_retptr(op);
2360-
}
2365+
Instruction::Return { .. } if self.gen.in_import => match self.sig.ret.scalar {
2366+
None => {
2367+
for op in operands.iter() {
2368+
self.store_in_retptr(op);
23612369
}
2362-
Some(Scalar::Void) => {
2363-
assert!(operands.is_empty());
2364-
}
2365-
Some(Scalar::Type(_)) => {
2366-
assert_eq!(operands.len(), 1);
2367-
self.src.push_str("return ");
2368-
self.src.push_str(&operands[0]);
2369-
self.src.push_str(";\n");
2370-
}
2371-
Some(Scalar::OptionBool(_)) => {
2372-
assert_eq!(operands.len(), 1);
2373-
let variant = &operands[0];
2370+
}
2371+
Some(Scalar::Void) => {
2372+
assert!(operands.is_empty());
2373+
}
2374+
Some(Scalar::Type(_)) => {
2375+
assert_eq!(operands.len(), 1);
2376+
self.src.push_str("return ");
2377+
self.src.push_str(&operands[0]);
2378+
self.src.push_str(";\n");
2379+
}
2380+
Some(Scalar::OptionBool(o)) => {
2381+
assert_eq!(operands.len(), 1);
2382+
let variant = &operands[0];
2383+
if !self.gen.is_empty_type(&o) {
23742384
self.store_in_retptr(&format!("{}.val", variant));
2375-
self.src.push_str("return ");
2376-
self.src.push_str(&variant);
2377-
self.src.push_str(".is_some;\n");
23782385
}
2379-
Some(Scalar::ResultBool(has_ok_type)) => {
2380-
assert_eq!(operands.len(), 1);
2381-
let variant = &operands[0];
2382-
assert!(self.sig.retptrs.len() <= 2);
2383-
uwriteln!(self.src, "if (!{}.is_err) {{", variant);
2386+
self.src.push_str("return ");
2387+
self.src.push_str(&variant);
2388+
self.src.push_str(".is_some;\n");
2389+
}
2390+
Some(Scalar::ResultBool(ok, err)) => {
2391+
assert_eq!(operands.len(), 1);
2392+
let variant = &operands[0];
2393+
assert!(self.sig.retptrs.len() <= 2);
2394+
uwriteln!(self.src, "if (!{}.is_err) {{", variant);
2395+
if let Some(_) = self.gen.get_nonempty_type(ok.as_ref()) {
23842396
if self.sig.retptrs.len() == 2 {
23852397
self.store_in_retptr(&format!("{}.val.ok", variant));
2386-
} else if self.sig.retptrs.len() == 1 && has_ok_type {
2398+
} else if self.sig.retptrs.len() == 1 && ok.is_some() {
23872399
self.store_in_retptr(&format!("{}.val.ok", variant));
23882400
}
2389-
uwriteln!(
2390-
self.src,
2391-
" return 1;
2401+
}
2402+
uwriteln!(
2403+
self.src,
2404+
" return 1;
23922405
}} else {{"
2393-
);
2406+
);
2407+
if let Some(_) = self.gen.get_nonempty_type(err.as_ref()) {
23942408
if self.sig.retptrs.len() == 2 {
23952409
self.store_in_retptr(&format!("{}.val.err", variant));
2396-
} else if self.sig.retptrs.len() == 1 && !has_ok_type {
2410+
} else if self.sig.retptrs.len() == 1 && !ok.is_some() {
23972411
self.store_in_retptr(&format!("{}.val.err", variant));
23982412
}
2399-
uwriteln!(
2400-
self.src,
2401-
" return 0;
2402-
}}"
2403-
);
24042413
}
2414+
uwriteln!(
2415+
self.src,
2416+
" return 0;
2417+
}}"
2418+
);
24052419
}
2406-
self.check_all_retptrs_written();
2407-
}
2420+
},
24082421
Instruction::Return { amt, .. } => {
24092422
assert!(*amt <= 1);
24102423
if *amt == 1 {

tests/codegen/option-result.wit

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
interface option-result {
2+
record empty {}
3+
record o-one {
4+
a: option<bool>,
5+
}
6+
7+
record o-nested {
8+
a: option<option<o-one>>,
9+
}
10+
11+
type o1 = option<o-one>
12+
type o2 = option<empty>
13+
type o3 = option<o-nested>
14+
type o4 = option<option<o-nested>>
15+
16+
type r1 = result
17+
type r2 = result<_, empty>
18+
type r3 = result<empty>
19+
type r4 = result<empty, empty>
20+
type r5 = result<option<o-one>, o1>
21+
type r6 = result<option<option<o-one>>, o2>
22+
type r7 = result<option<option<o-one>>, o4>
23+
24+
25+
type o5 = option<result>
26+
type o6 = option<result<option<result>>>
27+
28+
29+
o1-arg: func(x: o1)
30+
o1-result: func() -> o1
31+
32+
o2-arg: func(x: o2)
33+
o2-result: func() -> o2
34+
35+
o3-arg: func(x: o3)
36+
o3-result: func() -> o3
37+
38+
o4-arg: func(x: o4)
39+
o4-result: func() -> o4
40+
41+
o5-arg: func(x: o5)
42+
o5-result: func() -> o5
43+
44+
o6-arg: func(x: o6)
45+
o6-result: func() -> o6
46+
47+
r1-arg: func(x: r1)
48+
r1-result: func() -> r1
49+
50+
r2-arg: func(x: r2)
51+
r2-result: func() -> r2
52+
53+
r3-arg: func(x: r3)
54+
r3-result: func() -> r3
55+
56+
r4-arg: func(x: r4)
57+
r4-result: func() -> r4
58+
59+
r5-arg: func(x: r5)
60+
r5-result: func() -> r5
61+
62+
r6-arg: func(x: r6)
63+
r6-result: func() -> r6
64+
65+
r7-arg: func(x: r7)
66+
r7-result: func() -> r7
67+
68+
multi: func(x: r7, y: r7) -> (a: r7, b:r7, c: r7)
69+
multi-option: func(x: r7, y: r7) -> option<tuple<r7, r7>>
70+
}
71+
72+
default world my-world {
73+
import imports: self.option-result
74+
export exports: self.option-result
75+
}
76+

0 commit comments

Comments
 (0)