Skip to content

Commit c36517b

Browse files
authored
feat: update go bindings to pass go vet (#1670)
* feat: update go bindings to pass go vet Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com> * fix: small refactor for clarity Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com> --------- Signed-off-by: Andrew Steurer <94206073+asteurer@users.noreply.github.com>
1 parent a30b8dd commit c36517b

3 files changed

Lines changed: 103 additions & 24 deletions

File tree

‎crates/go/src/lib.rs‎

Lines changed: 92 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,26 @@ fn remote_pkg(name: &str) -> String {
4545
}
4646

4747
/// The version of github.com/bytecodealliance/go-pkg that's being used
48-
const REMOTE_PKG_VERSION: &str = "v0.2.2";
48+
const REMOTE_PKG_VERSION: &str = "v0.2.3";
4949

5050
/// If a user specifies the `pkg_name` flag, the required version for the
5151
/// shared remote package isn't recorded. This enables downstream users to retrieve the version programmatically.
5252
pub fn remote_pkg_version() -> String {
5353
format!("go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}")
5454
}
5555

56+
/// Appends `_` to `name` if it collides with a Go keyword.
57+
/// Source: https://go.dev/ref/spec#Keywords
58+
fn escape_go_keyword(name: String) -> String {
59+
match name.as_str() {
60+
"break" | "case" | "chan" | "const" | "continue" | "default" | "defer" | "else"
61+
| "fallthrough" | "for" | "func" | "go" | "goto" | "if" | "import" | "interface"
62+
| "map" | "package" | "range" | "return" | "select" | "struct" | "switch" | "type"
63+
| "var" => format!("{name}_"),
64+
_ => name,
65+
}
66+
}
67+
5668
#[derive(Default, Debug, Copy, Clone)]
5769
pub enum Format {
5870
#[default]
@@ -225,6 +237,8 @@ struct Go {
225237
types: HashSet<(String, TypeId)>,
226238
resources: HashMap<TypeId, Direction>,
227239
futures_and_streams: HashMap<(TypeId, bool), Option<WorldKey>>,
240+
// Tracks which `future`/`stream` declarations have already been generated.
241+
generated_futures_and_streams: HashSet<FutureStreamDedup>,
228242
}
229243

230244
impl Go {
@@ -571,16 +585,16 @@ func wasm_{kind}_drop_writable_{snake}(handle int32)
571585
{lower}
572586
573587
var wasm_{kind}_vtable_{snake} = witTypes.{upper_kind}Vtable[{payload}]{{
574-
{size},
575-
{align},
576-
wasm_{kind}_read_{snake},
577-
wasm_{kind}_write_{snake},
578-
nil,
579-
nil,
580-
wasm_{kind}_drop_readable_{snake},
581-
wasm_{kind}_drop_writable_{snake},
582-
{lift_name},
583-
{lower_name},
588+
Size: {size},
589+
Align: {align},
590+
Read: wasm_{kind}_read_{snake},
591+
Write: wasm_{kind}_write_{snake},
592+
CancelRead: nil,
593+
CancelWrite: nil,
594+
DropReadable: wasm_{kind}_drop_readable_{snake},
595+
DropWritable: wasm_{kind}_drop_writable_{snake},
596+
Lift: {lift_name},
597+
Lower: {lower_name},
584598
}}
585599
586600
func Make{upper_kind}{camel}() (*witTypes.{upper_kind}Writer[{payload}], *witTypes.{upper_kind}Reader[{payload}]) {{
@@ -1062,7 +1076,7 @@ impl Go {
10621076
func.params
10631077
.iter()
10641078
.skip(if has_self { 1 } else { 0 })
1065-
.map(|Param { name, .. }| name.to_lower_camel_case()),
1079+
.map(|Param { name, .. }| escape_go_keyword(name.to_lower_camel_case())),
10661080
)
10671081
.collect::<Vec<_>>();
10681082

@@ -1422,7 +1436,7 @@ func wasm_export_{name}({params}) {results} {{
14221436
.iter()
14231437
.skip(if has_self { 1 } else { 0 })
14241438
.map(|Param { name, ty, .. }| {
1425-
let name = name.to_lower_camel_case();
1439+
let name = escape_go_keyword(name.to_lower_camel_case());
14261440
let ty = self.type_name(resolve, *ty, interface, in_import, imports);
14271441
format!("{prefix}{name} {ty}")
14281442
})
@@ -1488,6 +1502,36 @@ func wasm_export_{name}({params}) {results} {{
14881502
if let hash_map::Entry::Vacant(e) = self.futures_and_streams.entry((ty, exported)) {
14891503
e.insert(interface.cloned());
14901504

1505+
let name = self.go_package_name(resolve, interface);
1506+
1507+
// Distinct `future`/`stream` types may share a
1508+
// payload type (e.g. when one payload is a type alias of the
1509+
// other, or when two anonymous payloads are structurally
1510+
// identical). Since the names of the generated declarations
1511+
// are derived from the payload type, generating code for each
1512+
// of them would produce duplicate declarations, so dedupe on
1513+
// the mangled payload name instead.
1514+
let kind = match &resolve.types[ty].kind {
1515+
TypeDefKind::Future(_) => "future",
1516+
TypeDefKind::Stream(_) => "stream",
1517+
_ => unreachable!(),
1518+
};
1519+
let snake = payload_type
1520+
.map(|ty| self.mangle_name(resolve, ty, interface))
1521+
.unwrap_or_else(|| "unit".into());
1522+
1523+
if !self
1524+
.generated_futures_and_streams
1525+
.insert(FutureStreamDedup {
1526+
in_import,
1527+
is_exported: exported,
1528+
pkg_name: name.clone(),
1529+
mangled_name: format!("{kind}_{snake}"),
1530+
})
1531+
{
1532+
continue;
1533+
}
1534+
14911535
let data = self.future_or_stream(
14921536
resolve,
14931537
ty,
@@ -1498,7 +1542,6 @@ func wasm_export_{name}({params}) {results} {{
14981542
&func.name,
14991543
);
15001544

1501-
let name = self.go_package_name(resolve, interface);
15021545
if in_import || !exported {
15031546
&mut self.interfaces
15041547
} else {
@@ -1525,7 +1568,7 @@ func wasm_export_{name}({params}) {results} {{
15251568
}
15261569

15271570
fn go_package_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1528-
match interface {
1571+
let name = match interface {
15291572
Some(WorldKey::Name(name)) => name.to_snake_case(),
15301573
Some(WorldKey::Interface(id)) => {
15311574
let interface = &resolve.interfaces[*id];
@@ -1550,7 +1593,9 @@ func wasm_export_{name}({params}) {results} {{
15501593
format!("{namespace}_{package}_{version}{interface}")
15511594
}
15521595
None => "wit_world".into(),
1553-
}
1596+
};
1597+
1598+
escape_go_keyword(name)
15541599
}
15551600

15561601
fn func_name(
@@ -1897,11 +1942,16 @@ for index := 0; index < int({length}); index++ {{
18971942
self.generator.tuples.insert(count);
18981943
self.imports.insert(remote_pkg("types"));
18991944

1900-
let results = (0..count)
1945+
let names = (0..count)
19011946
.map(|_| self.locals.tmp("result"))
1947+
.collect::<Vec<_>>();
1948+
let bindings = names.join(", ");
1949+
let fields = names
1950+
.iter()
1951+
.enumerate()
1952+
.map(|(idx, name)| format!("F{idx}: {name}"))
19021953
.collect::<Vec<_>>()
19031954
.join(", ");
1904-
19051955
let types = tuple
19061956
.types
19071957
.iter()
@@ -1911,8 +1961,8 @@ for index := 0; index < int({length}); index++ {{
19111961

19121962
uwriteln!(
19131963
self.src,
1914-
"{results} := {call}
1915-
{result} := witTypes.Tuple{count}[{types}]{{{results}}}"
1964+
"{bindings} := {call}
1965+
{result} := witTypes.Tuple{count}[{types}]{{{fields}}}"
19161966
);
19171967
} else {
19181968
uwriteln!(self.src, "{result} := {call}");
@@ -2088,7 +2138,12 @@ if {value} {{
20882138
.map(|&ty| self.type_name(resolve, ty))
20892139
.collect::<Vec<_>>()
20902140
.join(", ");
2091-
let fields = operands.join(", ");
2141+
let fields = operands
2142+
.iter()
2143+
.enumerate()
2144+
.map(|(idx, val)| format!("F{idx}: {val}"))
2145+
.collect::<Vec<String>>()
2146+
.join(", ");
20922147
self.imports.insert(remote_pkg("types"));
20932148
results.push(format!("witTypes.Tuple{count}[{types}]{{{fields}}}"));
20942149
}
@@ -2108,9 +2163,15 @@ if {value} {{
21082163
results.push(format!("({op}).{field}"));
21092164
}
21102165
}
2111-
Instruction::RecordLift { ty, .. } => {
2166+
Instruction::RecordLift { record, ty, .. } => {
21122167
let name = self.type_name(resolve, Type::Id(*ty));
2113-
let fields = operands.join(", ");
2168+
let fields = record
2169+
.fields
2170+
.iter()
2171+
.zip(operands.iter())
2172+
.map(|(field, op)| format!("{}: {op}", field.name.to_upper_camel_case()))
2173+
.collect::<Vec<_>>()
2174+
.join(", ");
21142175
results.push(format!("{name}{{{fields}}}"));
21152176
}
21162177
Instruction::OptionLower {
@@ -3286,3 +3347,11 @@ fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
32863347
Cow::Borrowed(code)
32873348
})
32883349
}
3350+
3351+
#[derive(Eq, PartialEq, Hash)]
3352+
struct FutureStreamDedup {
3353+
in_import: bool,
3354+
is_exported: bool,
3355+
pkg_name: String,
3356+
mangled_name: String,
3357+
}

‎crates/go/src/pkg‎

‎crates/test/src/go.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,16 @@ func main() {}
180180
fn verify(&self, runner: &Runner, verify: &Verify<'_>) -> Result<()> {
181181
replace_bindings_go_mod(runner, verify.bindings_dir)?;
182182

183+
// `go vet`
184+
runner.run_command(
185+
Command::new("go")
186+
.current_dir(&verify.bindings_dir)
187+
.arg("vet")
188+
.arg("-unsafeptr=false")
189+
.arg("./..."),
190+
)?;
191+
192+
// `go build`
183193
runner.run_command(
184194
Command::new("go")
185195
.current_dir(verify.bindings_dir)

0 commit comments

Comments
 (0)