Skip to content

Commit 6add188

Browse files
authored
Fix referring to foreign imported paths in Rust (#504)
This fixes the bindings generator for imports between interfaces to ensure that matches and lifts/lowers/etc all use the right name as opposed to assuming the name is already in scope. Closes #485
1 parent c2c2a3a commit 6add188

File tree

4 files changed

+82
-31
lines changed

4 files changed

+82
-31
lines changed

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,15 +1023,13 @@ impl Bindgen for FunctionBindgen<'_, '_> {
10231023
results.push(format!("(flags{}.bits() >> {}) as i32", tmp, i * 32));
10241024
}
10251025
}
1026-
Instruction::FlagsLift { name, flags, .. } => {
1026+
Instruction::FlagsLift { flags, ty, .. } => {
10271027
let repr = RustFlagsRepr::new(flags);
1028-
let name = name.to_upper_camel_case();
1029-
let mut result = format!("{}::empty()", name);
1028+
let name = self.gen.type_path(*ty, true);
1029+
let mut result = format!("{name}::empty()");
10301030
for (i, op) in operands.iter().enumerate() {
10311031
result.push_str(&format!(
1032-
" | {}::from_bits_preserve((({} as {repr}) << {}) as _)",
1033-
name,
1034-
op,
1032+
" | {name}::from_bits_preserve((({op} as {repr}) << {}) as _)",
10351033
i * 32
10361034
));
10371035
}
@@ -1246,9 +1244,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12461244
));
12471245
}
12481246

1249-
Instruction::EnumLower { enum_, name, .. } => {
1247+
Instruction::EnumLower { enum_, ty, .. } => {
12501248
let mut result = format!("match {} {{\n", operands[0]);
1251-
let name = name.to_upper_camel_case();
1249+
let name = self.gen.type_path(*ty, true);
12521250
for (i, case) in enum_.cases.iter().enumerate() {
12531251
let case = case.name.to_upper_camel_case();
12541252
result.push_str(&format!("{name}::{case} => {i},\n"));
@@ -1259,9 +1257,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12591257

12601258
// In unchecked mode when this type is a named enum then we know we
12611259
// defined the type so we can transmute directly into it.
1262-
Instruction::EnumLift { enum_, name, .. } if unchecked => {
1260+
Instruction::EnumLift { enum_, ty, .. } if unchecked => {
12631261
let mut result = format!("core::mem::transmute::<_, ");
1264-
result.push_str(&name.to_upper_camel_case());
1262+
result.push_str(&self.gen.type_path(*ty, true));
12651263
result.push_str(">(");
12661264
result.push_str(&operands[0]);
12671265
result.push_str(" as ");
@@ -1270,11 +1268,11 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12701268
results.push(result);
12711269
}
12721270

1273-
Instruction::EnumLift { enum_, name, .. } => {
1271+
Instruction::EnumLift { enum_, ty, .. } => {
12741272
let mut result = format!("match ");
12751273
result.push_str(&operands[0]);
12761274
result.push_str(" {\n");
1277-
let name = name.to_upper_camel_case();
1275+
let name = self.gen.type_path(*ty, true);
12781276
for (i, case) in enum_.cases.iter().enumerate() {
12791277
let case = case.name.to_upper_camel_case();
12801278
result.push_str(&format!("{i} => {name}::{case},\n"));

crates/gen-guest-teavm-java/tests/codegen.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use std::path::Path;
22
use std::process::Command;
33

44
macro_rules! codegen_test {
5+
// TODO: should fix this test
6+
(lift_lower_foreign $name:tt $test:tt) => {};
7+
58
($id:ident $name:tt $test:tt) => {
69
#[test]
710
fn $id() {

crates/gen-rust-lib/src/lib.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -204,22 +204,26 @@ pub trait RustGenerator<'a> {
204204
}
205205
}
206206

207+
fn type_path(&self, id: TypeId, param: bool) -> String {
208+
let name = if param {
209+
self.param_name(id)
210+
} else {
211+
self.result_name(id)
212+
};
213+
if let TypeOwner::Interface(id) = self.resolve().types[id].owner {
214+
if let Some(path) = self.path_to_interface(id) {
215+
return format!("{path}::{name}");
216+
}
217+
}
218+
name
219+
}
220+
207221
fn print_tyid(&mut self, id: TypeId, mode: TypeMode) {
208222
let info = self.info(id);
209223
let lt = self.lifetime_for(&info, mode);
210224
let ty = &self.resolve().types[id];
211225
if ty.name.is_some() {
212-
let name = if lt.is_some() {
213-
self.param_name(id)
214-
} else {
215-
self.result_name(id)
216-
};
217-
if let TypeOwner::Interface(id) = ty.owner {
218-
if let Some(path) = self.path_to_interface(id) {
219-
self.push_str(&path);
220-
self.push_str("::");
221-
}
222-
}
226+
let name = self.type_path(id, lt.is_some());
223227
self.push_str(&name);
224228

225229
// If the type recursively owns data and it's a
@@ -1094,17 +1098,19 @@ pub trait RustFunctionGenerator {
10941098
}
10951099

10961100
fn typename_lower(&self, id: TypeId) -> String {
1097-
match self.lift_lower() {
1098-
LiftLower::LowerArgsLiftResults => self.rust_gen().param_name(id),
1099-
LiftLower::LiftArgsLowerResults => self.rust_gen().result_name(id),
1100-
}
1101+
let param = match self.lift_lower() {
1102+
LiftLower::LowerArgsLiftResults => true,
1103+
LiftLower::LiftArgsLowerResults => false,
1104+
};
1105+
self.rust_gen().type_path(id, param)
11011106
}
11021107

11031108
fn typename_lift(&self, id: TypeId) -> String {
1104-
match self.lift_lower() {
1105-
LiftLower::LiftArgsLowerResults => self.rust_gen().param_name(id),
1106-
LiftLower::LowerArgsLiftResults => self.rust_gen().result_name(id),
1107-
}
1109+
let param = match self.lift_lower() {
1110+
LiftLower::LiftArgsLowerResults => true,
1111+
LiftLower::LowerArgsLiftResults => false,
1112+
};
1113+
self.rust_gen().type_path(id, param)
11081114
}
11091115
}
11101116

tests/codegen/lift-lower-foreign.wit

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
interface a {
2+
type t1 = u32
3+
record t2 { a: t1 }
4+
flags t3 { a, b, c }
5+
type t4 = tuple<t1, t2, t3>
6+
variant t5 { a, b(t2), c(t3) }
7+
enum t6 { a, b, c }
8+
type t7 = option<t2>
9+
type t8 = result<t2, t3>
10+
union t9 { t1, t2, t3, t4, u32 }
11+
}
12+
13+
interface the-interface {
14+
use self.a.{t1 as u1, t2 as u2, t3 as u3, t4 as u4, t5 as u5}
15+
use self.a.{t6 as u6, t7 as u7, t8 as %u8, t9 as u9}
16+
17+
f1: func(a: u1) -> u1
18+
f2: func(a: u2) -> u2
19+
f3: func(a: u3) -> u3
20+
f4: func(a: u4) -> u4
21+
f5: func(a: u5) -> u5
22+
f6: func(a: u6) -> u6
23+
f7: func(a: u7) -> u7
24+
f8: func(a: %u8) -> %u8
25+
f9: func(a: u9) -> u9
26+
}
27+
28+
default world foo {
29+
use self.a.{t1 as u1, t2 as u2, t3 as u3, t4 as u4, t5 as u5}
30+
use self.a.{t6 as u6, t7 as u7, t8 as %u8, t9 as u9}
31+
32+
export f1: func(a: u1) -> u1
33+
export f2: func(a: u2) -> u2
34+
export f3: func(a: u3) -> u3
35+
export f4: func(a: u4) -> u4
36+
export f5: func(a: u5) -> u5
37+
export f6: func(a: u6) -> u6
38+
export f7: func(a: u7) -> u7
39+
export f8: func(a: %u8) -> %u8
40+
export f9: func(a: u9) -> u9
41+
42+
import the-import: self.the-interface
43+
export the-export: self.the-interface
44+
}

0 commit comments

Comments
 (0)