Skip to content

[Rust] Generated variant types are not scoped when generated under mod wit_stream #1475

@jonathan-haubrich

Description

@jonathan-haubrich

When using a variant as the specified type for a stream, the type name is not scoped under the wit_stream mod. This causes error messages like:

  Compiling witbindgen-demo v0.1.0 (C:\Users\dweller\source\repos\witbindgen-demo)                                                                                                                   
error[E0412]: cannot find type `ControlMessage` in this scope                                                                                                                                         
  --> C:\Users\user\source\repos\witbindgen-demo\target\debug\build\wit-bindgen-rust-macro-98169ddaab8381ff\out\module0.rs:160:41                                                                 
   |
160 |         unsafe fn lift(ptr: *mut u8) -> ControlMessage {
   |                                         ^^^^^^^^^^^^^^ not found in this scope
   |
help: consider importing this enum
   |
114 +         use crate::ControlMessage;
   |

error[E0433]: failed to resolve: use of undeclared type `ControlMessage`
  --> C:\Users\user\source\repos\witbindgen-demo\target\debug\build\wit-bindgen-rust-macro-98169ddaab8381ff\out\module0.rs:214:25
   |
214 |                         ControlMessage::MethodCall(e13)
   |                         ^^^^^^^^^^^^^^ use of undeclared type `ControlMessage`
   |
help: consider importing this enum
   |
114 +         use crate::ControlMessage;
   |

error[E0433]: failed to resolve: use of undeclared type `ControlMessage`
  --> C:\Users\user\source\repos\witbindgen-demo\target\debug\build\wit-bindgen-rust-macro-98169ddaab8381ff\out\module0.rs:232:25
   |
232 |                         ControlMessage::ModuleMessage(e13)
   |                         ^^^^^^^^^^^^^^ use of undeclared type `ControlMessage`
   |
help: consider importing this enum
   |
114 +         use crate::ControlMessage;

Example wit file:

package demo:module@1.0.0;

world module {
    include wasi:io/imports@0.2.6;

    variant control-message {
        method-call(tuple<string, list<string>>),
        module-message(list<u8>),
    }

    export run: async func(control-stream: stream<control-message>);
}

Generated with:

wit_bindgen::generate!({
    world: "module",
    path: r#"wit"#,
    with: {
        "wasi:io/streams@0.2.6": wasi::io::streams,
        "wasi:io/error@0.2.6": wasi::io::error,
        "wasi:io/poll@0.2.6": wasi::io::poll,
    },
    debug: true,
});

Cargo.toml:

[package]
name = "witbindgen-demo"
version = "0.1.0"
edition = "2024"

[dependencies]
wasi = "0.14.7"
wit-bindgen = "0.49.0"

I was able to fix it by prepending crate:: where the variant name is being generated. It works for my use case, but it's not robust (it breaks when defining the variant inside an interface for example).

diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs
index df362347..eeda6565 100644
--- a/crates/rust/src/bindgen.rs
+++ b/crates/rust/src/bindgen.rs
@@ -527,7 +527,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
                 self.push_str(&format!("match {op0} {{\n"));
                 for (case, block) in variant.cases.iter().zip(blocks) {
                     let case_name = case.name.to_upper_camel_case();
-                    self.push_str(&format!("{name}::{case_name}"));
+                    self.push_str(&format!("crate::{name}::{case_name}"));
                     if case.ty.is_some() {
                         self.push_str(&format!("(e) => {block},\n"));
                     } else {
@@ -569,10 +569,10 @@ impl Bindgen for FunctionBindgen<'_, '_> {
                     }
                     let case_name = case.name.to_upper_camel_case();
                     if case.ty.is_none() {
-                        uwriteln!(self.src, "{name}::{case_name}");
+                        uwriteln!(self.src, "crate::{name}::{case_name}");
                     } else {
                         uwriteln!(self.src, "let e{tmp} = {block};");
-                        uwriteln!(self.src, "{name}::{case_name}(e{tmp})");
+                        uwriteln!(self.src, "crate::{name}::{case_name}(e{tmp})");
                     }
                     uwriteln!(self.src, "}}");
                 }
diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs
index c9a55eb1..e89cad02 100644
--- a/crates/rust/src/interface.rs
+++ b/crates/rust/src/interface.rs
@@ -583,8 +583,8 @@ macro_rules! {macro_name} {{
             PayloadFor::Future => "",
             PayloadFor::Stream => ", _: usize",
         };
-        let mut lift_fn = format!("unsafe fn lift(ptr: *mut u8) -> {name} {{ {lift} }}");
-        let mut lower_fn = format!("unsafe fn lower(value: {name}, ptr: *mut u8) {{ {lower} }}");
+        let mut lift_fn = format!("unsafe fn lift(ptr: *mut u8) -> crate::{name} {{ {lift} }}");
+        let mut lower_fn = format!("unsafe fn lower(value: crate::{name}, ptr: *mut u8) {{ {lower} }}");
         let mut dealloc_lists_fn =
             format!("unsafe fn dealloc_lists(ptr: *mut u8) {{ {dealloc_lists} }}");
         let mut lift_arg = "lift";
@@ -655,7 +655,7 @@ pub mod vtable{ordinal} {{
     {lower_fn}
     {dealloc_lists_fn}
 
-    pub static VTABLE: {async_support}::{camel}Vtable<{name}> = {async_support}::{camel}Vtable::<{name}> {{
+    pub static VTABLE: {async_support}::{camel}Vtable<crate::{name}> = {async_support}::{camel}Vtable::<crate::{name}> {{
         cancel_write,
         cancel_read,
         drop_writable,
@@ -671,7 +671,7 @@ pub mod vtable{ordinal} {{
         start_write,
     }};
 
-    impl super::{camel}Payload for {name} {{
+    impl super::{camel}Payload for crate::{name} {{
         const VTABLE: &'static {async_support}::{camel}Vtable<Self> = &VTABLE;
     }}
 }}

Metadata

Metadata

Assignees

No one assigned

    Labels

    asyncRelated to async/streams in the component model.gen-rustRelated to bindings for Rust-compiled-to-WebAssembly

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions