Repository: bytecodealliance/wasmtime
Pull request #8305 (2024-04-05 18:40:16)

fix: bindgen trappable_errors using unversion/versioned packages
This PR fixes a bug in the `wasmtime::bindgen!` macro when specifying `trappable_errors` and there is a versioned and unversioned representation of a package. 

fibonacci1729: cc/ @alexcrichton 

Patch:
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 2f92db841..b07ac4c4d 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -1,6 +1,6 @@
 use crate::rust::{to_rust_ident, to_rust_upper_camel_case, RustGenerator, TypeMode};
 use crate::types::{TypeInfo, Types};
-use anyhow::{anyhow, bail, Context};
+use anyhow::{bail, Context};
 use heck::*;
 use indexmap::{IndexMap, IndexSet};
 use std::collections::{BTreeMap, HashMap, HashSet};
@@ -968,9 +968,13 @@ fn resolve_type_in_package(resolve: &Resolve, wit_path: &str) -> anyhow::Result<
         .flat_map(|l| l)
         .collect::<HashSet<_>>();
 
+    let mut found_interface = false;
+
     // Look for an interface whose assigned prefix starts `wit_path`. Not
     // exactly the most efficient thing ever but is sufficient for now.
     for (id, interface) in resolve.interfaces.iter() {
+        found_interface = true;
+
         let iface_name = match &interface.name {
             Some(name) => name,
             None => continue,
@@ -988,15 +992,20 @@ fn resolve_type_in_package(resolve: &Resolve, wit_path: &str) -> anyhow::Result<
             Some(rest) => rest,
             None => continue,
         };
-        let wit_path = wit_path
-            .strip_prefix('/')
-            .ok_or_else(|| anyhow!("expected `/` after interface name"))?;
 
-        return interface
-            .types
-            .get(wit_path)
-            .copied()
-            .ok_or_else(|| anyhow!("no types found to match `{wit_path}` in interface"));
+        let wit_path = match wit_path.strip_prefix('/') {
+            Some(rest) => rest,
+            None => continue,
+        };
+
+        match interface.types.get(wit_path).copied() {
+            Some(type_id) => return Ok(type_id),
+            None => continue,
+        }
+    }
+
+    if found_interface {
+        bail!("no types found to match `{wit_path}` in interface");
     }
 
     bail!("no package/interface found to match `{wit_path}`")


Test patch:
diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs
index da2f0550d..a292d8004 100644
--- a/crates/component-macro/tests/codegen.rs
+++ b/crates/component-macro/tests/codegen.rs
@@ -107,6 +107,33 @@ mod with_key_and_resources {
     }
 }
 
+mod trappable_errors_with_versioned_and_unversioned_packages {
+    wasmtime::component::bindgen!({
+        inline: "
+            package foo:foo@0.1.0;
+
+            interface a {
+                variant error {
+                    other(string),
+                }
+
+                f: func() -> result<_, error>;
+            }
+
+            world foo {
+                import a;
+            }
+        ",
+        path: "tests/codegen/unversioned-foo.wit",
+        trappable_error_type: {
+            "foo:foo/a@0.1.0/error" => MyX,
+        },
+    });
+
+    #[allow(dead_code)]
+    type MyX = u64;
+}
+
 mod trappable_errors {
     wasmtime::component::bindgen!({
         inline: "
diff --git a/crates/component-macro/tests/codegen/unversioned-foo.wit b/crates/component-macro/tests/codegen/unversioned-foo.wit
new file mode 100644
index 000000000..a7b3bb616
--- /dev/null
+++ b/crates/component-macro/tests/codegen/unversioned-foo.wit
@@ -0,0 +1,12 @@
+package foo:foo;
+
+interface a {
+    variant error {
+        other(string),
+    }
+    g: func() -> result<_, error>;
+}
+
+world nope {
+    import a;
+}
\ No newline at end of file