diff --git a/crates/component-macro/build.rs b/crates/component-macro/build.rs new file mode 100644 index 000000000000..be0ad5bc97cb --- /dev/null +++ b/crates/component-macro/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let out_dir = std::env::var("OUT_DIR").unwrap(); + println!("cargo:rustc-env=DEBUG_OUTPUT_DIR={out_dir}"); +} diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs index 096126be27ee..3613541080a0 100644 --- a/crates/component-macro/src/bindgen.rs +++ b/crates/component-macro/src/bindgen.rs @@ -3,6 +3,7 @@ use quote::ToTokens; use std::collections::HashMap; use std::collections::HashSet; use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::{braced, token, Token}; @@ -24,7 +25,31 @@ pub fn expand(input: &Config) -> Result { )); } - let src = input.opts.generate(&input.resolve, input.world); + let mut src = input.opts.generate(&input.resolve, input.world); + + // If a magical `WASMTIME_DEBUG_BINDGEN` environment variable is set then + // place a formatted version of the expanded code into a file. This file + // will then show up in rustc error messages for any codegen issues and can + // be inspected manually. + if std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() { + static INVOCATION: AtomicUsize = AtomicUsize::new(0); + let root = Path::new(env!("DEBUG_OUTPUT_DIR")); + let world_name = &input.resolve.worlds[input.world].name; + let n = INVOCATION.fetch_add(1, Relaxed); + let path = root.join(format!("{world_name}{n}.rs")); + + std::fs::write(&path, &src).unwrap(); + + // optimistically format the code but don't require success + drop( + std::process::Command::new("rustfmt") + .arg(&path) + .arg("--edition=2021") + .output(), + ); + + src = format!("include!({path:?});"); + } let mut contents = src.parse::().unwrap(); // Include a dummy `include_str!` for any files we read so rustc knows that diff --git a/crates/component-macro/tests/codegen/wat.wit b/crates/component-macro/tests/codegen/wat.wit new file mode 100644 index 000000000000..cba93e0d4fd8 --- /dev/null +++ b/crates/component-macro/tests/codegen/wat.wit @@ -0,0 +1,10 @@ +package same:name; + +interface this-name-is-duplicated { + resource this-name-is-duplicated { + } +} + +world example { + export this-name-is-duplicated; +} diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index a73f6bcca4e5..c9dd0455a463 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -362,13 +362,13 @@ impl Wasmtime { gen.gen.name_interface(resolve, *id, name, true); gen.current_interface = Some((*id, name, true)); gen.types(*id); + let struct_name = "Guest"; let iface = &resolve.interfaces[*id]; let iface_name = match name { WorldKey::Name(name) => name, WorldKey::Interface(_) => iface.name.as_ref().unwrap(), }; - let camel = to_rust_upper_camel_case(iface_name); - uwriteln!(gen.src, "pub struct {camel} {{"); + uwriteln!(gen.src, "pub struct {struct_name} {{"); for (_, func) in iface.functions.iter() { uwriteln!( gen.src, @@ -378,13 +378,13 @@ impl Wasmtime { } uwriteln!(gen.src, "}}"); - uwriteln!(gen.src, "impl {camel} {{"); + uwriteln!(gen.src, "impl {struct_name} {{"); uwrite!( gen.src, " pub fn new( __exports: &mut wasmtime::component::ExportInstance<'_, '_>, - ) -> wasmtime::Result<{camel}> {{ + ) -> wasmtime::Result<{struct_name}> {{ " ); let mut fields = Vec::new(); @@ -393,7 +393,7 @@ impl Wasmtime { uwriteln!(gen.src, "let {name} = {getter};"); fields.push(name); } - uwriteln!(gen.src, "Ok({camel} {{"); + uwriteln!(gen.src, "Ok({struct_name} {{"); for name in fields { uwriteln!(gen.src, "{name},"); } @@ -467,7 +467,7 @@ impl Wasmtime { let (path, method_name) = match pkgname { Some(pkgname) => ( format!( - "exports::{}::{}::{snake}::{camel}", + "exports::{}::{}::{snake}::{struct_name}", pkgname.namespace.to_snake_case(), self.name_package_module(resolve, iface.package.unwrap()), ), @@ -477,7 +477,7 @@ impl Wasmtime { self.name_package_module(resolve, iface.package.unwrap()) ), ), - None => (format!("exports::{snake}::{camel}"), snake.clone()), + None => (format!("exports::{snake}::{struct_name}"), snake.clone()), }; let getter = format!( "\ @@ -519,7 +519,13 @@ impl Wasmtime { self.toplevel_import_trait(resolve, world); uwriteln!(self.src, "const _: () = {{"); - uwriteln!(self.src, "use wasmtime::component::__internal::anyhow;"); + uwriteln!( + self.src, + " + #[allow(unused_imports)] + use wasmtime::component::__internal::anyhow; + " + ); uwriteln!(self.src, "impl {camel} {{"); self.toplevel_add_to_linker(resolve, world); @@ -1011,14 +1017,6 @@ impl<'a> InterfaceGenerator<'a> { uwriteln!(self.src, "}}"); } else { - let iface_name = match self.current_interface.unwrap().1 { - WorldKey::Name(name) => name.to_upper_camel_case(), - WorldKey::Interface(i) => self.resolve.interfaces[*i] - .name - .as_ref() - .unwrap() - .to_upper_camel_case(), - }; self.rustdoc(docs); uwriteln!( self.src, @@ -1026,7 +1024,7 @@ impl<'a> InterfaceGenerator<'a> { pub type {camel} = wasmtime::component::ResourceAny; pub struct Guest{camel}<'a> {{ - funcs: &'a {iface_name}, + funcs: &'a Guest, }} " );