From ec7cc0ab05b86b10da581b14cc9c5140aa07883e Mon Sep 17 00:00:00 2001 From: Michael Pawliszyn Date: Fri, 25 Sep 2026 09:24:20 -0400 Subject: [PATCH 1/3] Adds a codegen test for maps in world level functions, failing for rust. Rust bindings fail to compile for functions that are directly imported or exported from a world. Existing map tests use interfaces. `Interface::finish` only imports `WitMap` when the path to root is non-empty so worlds never get it. --- crates/test/src/d.rs | 6 +++++- tests/codegen/map-in-world.wit | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tests/codegen/map-in-world.wit diff --git a/crates/test/src/d.rs b/crates/test/src/d.rs index 43563ce2b..ad6a9db73 100644 --- a/crates/test/src/d.rs +++ b/crates/test/src/d.rs @@ -31,7 +31,11 @@ impl LanguageMethods for D { config: &crate::config::WitConfig, _args: &[String], ) -> bool { - config.async_ || config.error_context || name == "map.wit" || name == "issue1642.wit" + config.async_ + || config.error_context + || name == "map.wit" + || name == "map-in-world.wit" + || name == "issue1642.wit" } fn default_bindgen_args_for_codegen(&self) -> &[&str] { diff --git a/tests/codegen/map-in-world.wit b/tests/codegen/map-in-world.wit new file mode 100644 index 000000000..eb8cc5db3 --- /dev/null +++ b/tests/codegen/map-in-world.wit @@ -0,0 +1,6 @@ +package foo:foo; + +world map-in-world { + import take-map: func(a: map); + export return-map: func() -> map; +} From 910b3f8cae092180a57e00b5d76533afe56ae807 Mon Sep 17 00:00:00 2001 From: Michael Pawliszyn Date: Fri, 25 Sep 2026 10:16:58 -0400 Subject: [PATCH 2/3] Adds test for a WIT map type named `wit-map`. This currently fails in rust since it ends up clashing with the generated WitMap. --- crates/test/src/d.rs | 1 + tests/codegen/map-named-wit-map.wit | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/codegen/map-named-wit-map.wit diff --git a/crates/test/src/d.rs b/crates/test/src/d.rs index ad6a9db73..f11692146 100644 --- a/crates/test/src/d.rs +++ b/crates/test/src/d.rs @@ -35,6 +35,7 @@ impl LanguageMethods for D { || config.error_context || name == "map.wit" || name == "map-in-world.wit" + || name == "map-named-wit-map.wit" || name == "issue1642.wit" } diff --git a/tests/codegen/map-named-wit-map.wit b/tests/codegen/map-named-wit-map.wit new file mode 100644 index 000000000..e82d9f790 --- /dev/null +++ b/tests/codegen/map-named-wit-map.wit @@ -0,0 +1,10 @@ +package foo:foo; + +interface wit-map { + type wit-map = map; + f: func(a: wit-map); +} + +world map-named-wit-map { + import wit-map; +} From 172582b3cd912c4d9a3a8009231975fb8c4104b1 Mon Sep 17 00:00:00 2001 From: Michael Pawliszyn Date: Fri, 25 Sep 2026 10:36:06 -0400 Subject: [PATCH 3/3] Fixing rust map lowering interfaces by scoping each use. Importing the trait anonymously inside the lowering block rather than trying to combine imports and correctly importing once per interface. This missed both maps existing in the world and caused a potential name collision. I claim this should not change the final compiled code nor change the compile time much. I also clean up the logic trying to import once per interface. --- crates/rust/src/bindgen.rs | 11 ++++------- crates/rust/src/interface.rs | 8 +------- crates/rust/src/lib.rs | 7 ------- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 70aeb67a5..ab2275998 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -775,12 +775,7 @@ impl Bindgen for FunctionBindgen<'_, '_> { } => { let alloc = self.r#gen.path_to_std_alloc_module(); let rt = self.r#gen.r#gen.runtime_path().to_string(); - self.r#gen.needs_wit_map = true; - self.r#gen.needs_runtime_module = true; - self.r#gen - .r#gen - .rt_module - .insert(crate::RuntimeItem::WitMapTrait); + let wit_map = self.r#gen.r#gen.wit_map_path(); let body = self.blocks.pop().unwrap(); let tmp = self.tmp(); let map = format!("map{tmp}"); @@ -792,7 +787,9 @@ impl Bindgen for FunctionBindgen<'_, '_> { "let {map} = {operand0};\n", operand0 = operands[0] )); - self.push_str(&format!("let {len} = {map}.wit_map_len();\n")); + self.push_str(&format!( + "let {len} = {{ use {wit_map} as _; {map}.wit_map_len() }};\n" + )); let entry = self.map_entry_layout(key, value); self.push_str(&format!( "let {layout} = {alloc}::Layout::from_size_align({len} * {}, {}).unwrap();\n", diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index c79a22a55..48121ac30 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -27,7 +27,6 @@ pub struct InterfaceGenerator<'a> { pub return_pointer_area_size: ArchitectureSize, pub return_pointer_area_align: Alignment, pub(super) needs_runtime_module: bool, - pub(super) needs_wit_map: bool, } /// A description of the "mode" in which a type is printed. @@ -449,12 +448,7 @@ macro_rules! {macro_name} {{ if self.needs_runtime_module { let root = self.path_to_root(); if !root.is_empty() { - let wit_map_use = if self.needs_wit_map { - format!("use {root}_rt::WitMap;\n") - } else { - String::new() - }; - return format!("use {root}_rt;\n{wit_map_use}{src}"); + return format!("use {root}_rt;\n{src}"); } } src diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 94a2dacca..7a2058937 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -116,7 +116,6 @@ enum RuntimeItem { AsF64, ResourceType, BoxType, - WitMapTrait, } #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -423,7 +422,6 @@ impl RustWasm { return_pointer_area_size: Default::default(), return_pointer_area_align: Default::default(), needs_runtime_module: false, - needs_wit_map: false, }) } @@ -755,11 +753,6 @@ pub fn run_ctors_once() {{ self.emit_runtime_as_trait("f64", &["f64"]); } - RuntimeItem::WitMapTrait => { - let rt = self.runtime_path().to_string(); - uwriteln!(self.src, "pub use {rt}::WitMap;"); - } - RuntimeItem::ResourceType => { self.src.push_str( r#"