Skip to content

Commit 7bebfd6

Browse files
authored
Generate nominal IDs for all bindings generation (#1526)
* Generate nominal IDs for all bindings generation This commit leverages bytecodealliance/wasm-tools#2447 to make many existing and future problems much easier in `wit-bindgen`. Namely a `TypeId` now uniquely identifies a type to be generated rather than simultaneously representing both an import and an export in some situations. This isn't immediately leveraged in bindings generators just yet but it's intended to open up the doors to benefitting from this in the future. * Rely on nominal type ids in the rust generator No major changes just yet, but this shows some examples of removing non-obvious logic in bindings generation enabled by nominal type ids. * Fix Go CI
1 parent e4dc22b commit 7bebfd6

File tree

7 files changed

+49
-32
lines changed

7 files changed

+49
-32
lines changed

crates/c/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,18 @@ impl WorldGenerator for C {
186186
let world = &resolve.worlds[world];
187187
for (key, _item) in world.imports.iter().chain(world.exports.iter()) {
188188
let name = resolve.name_world_key(key);
189-
interfaces.insert(name, key.clone());
189+
interfaces
190+
.entry(name)
191+
.or_insert(Vec::new())
192+
.push(key.clone());
190193
}
191194

192195
for (from, to) in self.opts.rename.iter() {
193196
match interfaces.get(from) {
194-
Some(key) => {
195-
self.renamed_interfaces.insert(key.clone(), to.clone());
197+
Some(keys) => {
198+
for key in keys {
199+
self.renamed_interfaces.insert(key.clone(), to.clone());
200+
}
196201
}
197202
None => {
198203
eprintln!("warning: rename of `{from}` did not match any interfaces");

crates/core/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ pub enum Direction {
2323
}
2424

2525
pub trait WorldGenerator {
26-
fn generate(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
26+
fn generate(&mut self, resolve: &mut Resolve, id: WorldId, files: &mut Files) -> Result<()> {
27+
if self.uses_nominal_type_ids() {
28+
resolve.generate_nominal_type_ids(id);
29+
}
2730
let world = &resolve.worlds[id];
2831
self.preprocess(resolve, id);
2932

@@ -81,6 +84,13 @@ pub trait WorldGenerator {
8184
self.finish(resolve, id, files)
8285
}
8386

87+
/// Whether or not this bindings generator expects
88+
/// [`Resolve::generate_nominal_type_ids`] to be used before generating
89+
/// bindings.
90+
fn uses_nominal_type_ids(&self) -> bool {
91+
true
92+
}
93+
8494
fn finish_imports(&mut self, resolve: &Resolve, world: WorldId, files: &mut Files) {
8595
let _ = (resolve, world, files);
8696
}

crates/go/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,14 @@ func Lift{upper_kind}{camel}(handle int32) *wit_types.{upper_kind}Reader[{payloa
661661
}
662662

663663
impl WorldGenerator for Go {
664+
// FIXME(#1527): this caused failures in CI at
665+
// https://github.com/bytecodealliance/wit-bindgen/actions/runs/21880247244/job/63160400774?pr=1526
666+
// and should be fixed at some point by deleting this method and getting
667+
// tests passing again.
668+
fn uses_nominal_type_ids(&self) -> bool {
669+
false
670+
}
671+
664672
fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
665673
_ = world;
666674
self.sizes.fill(resolve);
@@ -1718,7 +1726,7 @@ for index, {ITER_ELEMENT} := range {slice} {{
17181726
for index := 0; index < int({length}); index++ {{
17191727
{ITER_BASE_POINTER} := unsafe.Add(unsafe.Pointer({value}), index * {size})
17201728
{body}
1721-
{result} = append({result}, {body_result})
1729+
{result} = append({result}, {body_result})
17221730
}}
17231731
"
17241732
);
@@ -2514,7 +2522,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
25142522
self.src,
25152523
"
25162524
{docs}type {name} struct {{
2517-
{fields}
2525+
{fields}
25182526
}}"
25192527
)
25202528
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,11 @@ fn parse_source(
242242
}
243243

244244
impl Config {
245-
fn expand(self) -> Result<TokenStream> {
245+
fn expand(mut self) -> Result<TokenStream> {
246246
let mut files = Default::default();
247247
let mut generator = self.opts.build();
248248
generator
249-
.generate(&self.resolve, self.world, &mut files)
249+
.generate(&mut self.resolve, self.world, &mut files)
250250
.map_err(|e| anyhow_to_syn(Span::call_site(), e))?;
251251
let (_, src) = files.iter().next().unwrap();
252252
let mut src = std::str::from_utf8(src).unwrap().to_string();

crates/rust/src/interface.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,23 +2441,7 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8)
24412441

24422442
pub fn is_exported_resource(&self, ty: TypeId) -> bool {
24432443
let ty = dealias(self.resolve, ty);
2444-
let ty = &self.resolve.types[ty];
2445-
match &ty.kind {
2446-
TypeDefKind::Resource => {}
2447-
_ => return false,
2448-
}
2449-
2450-
match ty.owner {
2451-
// Worlds cannot export types of any kind as of this writing.
2452-
TypeOwner::World(_) => false,
2453-
2454-
// Interfaces are "stateful" currently where whatever we last saw
2455-
// them as dictates whether it's exported or not.
2456-
TypeOwner::Interface(i) => !self.r#gen.interface_last_seen_as_import[&i],
2457-
2458-
// Shouldn't be the case for resources
2459-
TypeOwner::None => unreachable!(),
2460-
}
2444+
self.r#gen.exported_resources.contains(&ty)
24612445
}
24622446

24632447
fn push_string_name(&mut self) {

crates/rust/src/lib.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ pub struct RustWasm {
3636
export_modules: Vec<(String, Vec<String>)>,
3737
skip: HashSet<String>,
3838
interface_names: HashMap<InterfaceId, InterfaceName>,
39-
/// Each imported and exported interface is stored in this map. Value indicates if last use was import.
40-
interface_last_seen_as_import: HashMap<InterfaceId, bool>,
39+
exported_resources: HashSet<TypeId>,
4140
import_funcs_called: bool,
4241
with_name_counter: usize,
4342
// Track which interfaces and types are generated. Remapped interfaces and types provided via `with`
@@ -302,7 +301,7 @@ impl RustWasm {
302301
let world = resolve.select_world(&main_packages, world)?;
303302

304303
let mut files = Files::default();
305-
self.generate(&resolve, world, &mut files)?;
304+
self.generate(&mut resolve, world, &mut files)?;
306305
let out_dir = std::env::var("OUT_DIR").expect("cargo sets OUT_DIR");
307306
let (name, contents) = files
308307
.iter()
@@ -446,7 +445,8 @@ impl RustWasm {
446445
};
447446

448447
let remapped = entry.remapped;
449-
self.interface_names.insert(id, entry);
448+
let prev = self.interface_names.insert(id, entry);
449+
assert!(prev.is_none());
450450

451451
Ok(remapped)
452452
}
@@ -1117,6 +1117,18 @@ impl WorldGenerator for RustWasm {
11171117
}
11181118
}
11191119

1120+
for item in world.exports.values() {
1121+
let WorldItem::Interface { id, .. } = item else {
1122+
continue;
1123+
};
1124+
for id in resolve.interfaces[*id].types.values().copied() {
1125+
let TypeDefKind::Resource = &resolve.types[id].kind else {
1126+
continue;
1127+
};
1128+
assert!(self.exported_resources.insert(id));
1129+
}
1130+
}
1131+
11201132
for (k, v) in self.opts.with.iter() {
11211133
self.with.insert(k.clone(), v.clone().into());
11221134
}
@@ -1144,7 +1156,6 @@ impl WorldGenerator for RustWasm {
11441156
self.generated_types.insert(full_name);
11451157
}
11461158

1147-
self.interface_last_seen_as_import.insert(id, true);
11481159
let wasm_import_module = resolve.name_world_key(name);
11491160
let mut r#gen = self.interface(
11501161
Identifier::Interface(id, name),
@@ -1201,7 +1212,6 @@ impl WorldGenerator for RustWasm {
12011212
self.generated_types.insert(full_name);
12021213
}
12031214

1204-
self.interface_last_seen_as_import.insert(id, false);
12051215
let wasm_import_module = format!("[export]{}", resolve.name_world_key(name));
12061216
let mut r#gen = self.interface(
12071217
Identifier::Interface(id, name),

src/bin/wit-bindgen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ fn gen_world(
232232
main_packages.push(pkg);
233233
}
234234
let world = resolve.select_world(&main_packages, opts.world.as_deref())?;
235-
generator.generate(&resolve, world, files)?;
235+
generator.generate(&mut resolve, world, files)?;
236236

237237
Ok(())
238238
}

0 commit comments

Comments
 (0)