Repository: bytecodealliance/wit-bindgen (Rust)

Issue:
Code generation error for resources with `witx_bindgen_wasmtime::import!` with async enabled
`repro.witx`:

```witx
resource request {
    method: function() -> string
}
```

`main.rs`:

```rust
witx_bindgen_wasmtime::import!({
    paths: ["repro.witx"],
    async: []
});

struct Host;

#[derive(Debug)]
struct Request;

impl repro::Repro for Host {
    type Request = Request;

    fn request_method(&mut self, request: &Self::Request) -> String {
        unimplemented!()
    }
}

fn main() {
}
```

Compilation error:

```text
error[E0277]: `T` cannot be sent between threads safely
 --> src/main.rs:1:1
  |
1 | / witx_bindgen_wasmtime::import!({
2 | |     paths: ["repro.witx"],
3 | |     async: []
4 | | });
  | |___^ `T` cannot be sent between threads safely
  |
  = note: this error originates in the macro `witx_bindgen_wasmtime::import` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting type parameter `T`
  |
4 | });, T: std::marker::Send
  |    ^^^^^^^^^^^^^^^^^^^^^^
```

Expanded code:

```rust
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use witx_bindgen_wasmtime::{wasmtime, anyhow, bitflags};
mod repro {
    #[allow(unused_imports)]
    use witx_bindgen_wasmtime::{wasmtime, anyhow};
    pub trait Repro: Sized {
        type Request: std::fmt::Debug;
        fn request_method(&mut self, self_: &Self::Request) -> String;
        fn drop_request(&mut self, state: Self::Request) {
            drop(state);
        }
    }
    pub struct ReproTables<T: Repro> {
        pub(crate) request_table: witx_bindgen_wasmtime::Table<T::Request>,
    }
    impl<T: Repro> Default for ReproTables<T> {
        fn default() -> Self {
            Self {
                request_table: Default::default(),
            }
        }
    }
    pub fn add_repro_to_linker<T, U>(
        linker: &mut wasmtime::Linker<T>,
        get: impl Fn(&mut T) -> (&mut U, &mut ReproTables<U>) + Send + Sync + Copy + 'static,
    ) -> anyhow::Result<()>
    where
        U: Repro,
    {
        use witx_bindgen_wasmtime::rt::get_memory;
        use witx_bindgen_wasmtime::rt::get_func;
        linker.func_wrap2_async(
            "repro",
            "request::method",
            move |mut caller: wasmtime::Caller<'_, T>, arg0: i32, arg1: i32| {
                Box::new(async move {
                    let func = get_func(&mut caller, "canonical_abi_realloc")?;
                    let func_canonical_abi_realloc =
                        func.typed::<(i32, i32, i32, i32), i32, _>(&caller)?;
                    let memory = &get_memory(&mut caller, "memory")?;
                    let host = get(caller.data_mut());
                    let (host, _tables) = host;
                    let param0 = _tables
                        .request_table
                        .get((arg0) as u32)
                        .ok_or_else(|| wasmtime::Trap::new("invalid handle index"))?;
                    let result0 = host.request_method(param0);
                    let vec1 = result0;
                    let ptr1 = func_canonical_abi_realloc
                        .call_async(&mut caller, (0, 0, 1, (vec1.len() as i32) * 1))
                        .await?;
                    let (caller_memory, data) = memory.data_and_store_mut(&mut caller);
                    let (_, _tables) = get(data);
                    caller_memory.store_many(ptr1, vec1.as_ref())?;
                    caller_memory.store(
                        arg1 + 8,
                        witx_bindgen_wasmtime::rt::as_i32(vec1.len() as i32),
                    )?;
                    caller_memory.store(arg1 + 0, witx_bindgen_wasmtime::rt::as_i32(ptr1))?;
                    Ok(())
                })
            },
        )?;
        linker.func_wrap(
            "canonical_abi",
            "resource_drop_request",
            move |mut caller: wasmtime::Caller<'_, T>, handle: u32| {
                let (host, tables) = get(caller.data_mut());
                let handle = tables.request_table.remove(handle).map_err(|e| {
                    wasmtime::Trap::new({
                        let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
                            &["failed to remove handle: "],
                            &match (&e,) {
                                (arg0,) => [::core::fmt::ArgumentV1::new(
                                    arg0,
                                    ::core::fmt::Display::fmt,
                                )],
                            },
                        ));
                        res
                    })
                })?;
                host.drop_request(handle);
                Ok(())
            },
        )?;
        Ok(())
    }
    use witx_bindgen_wasmtime::rt::RawMem;
}
struct Host;
struct Request;
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Request {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match *self {
            Request => {
                let debug_trait_builder = &mut ::core::fmt::Formatter::debug_tuple(f, "Request");
                ::core::fmt::DebugTuple::finish(debug_trait_builder)
            }
        }
    }
}
impl repro::Repro for Host {
    type Request = Request;
    fn request_method(&mut self, request: &Self::Request) -> String {
        ::core::panicking::panic("not implemented")
    }
}
fn main() {}
```

The compilation error for the expanded code points at `T` from `add_repro_to_linker`:

```text
error[E0277]: `T` cannot be sent between threads safely
  --> src/main.rs:55:26
   |
55 |                         .call_async(&mut caller, (0, 0, 1, (vec1.len() as i32) * 1))
   |                          ^^^^^^^^^^ `T` cannot be sent between threads safely
   |
help: consider further restricting type parameter `T`
   |
33 |         U: Repro, T: std::marker::Send
```

With `T: Send` added to `add_repro_to_linker`, it still errors because both `U` is not marked `Send` and `<U as Repro>::Request` is not marked `Send + Sync`.

It compiles with the following constraints:

```rust
pub trait Repro: Sized {
    type Request: std::fmt::Debug + Send + Sync;
    ...
}

...
pub fn add_repro_to_linker<T, U>(...)
where
    U: Repro + Send,
    T: Send
{
    ...
}
```


Discussion:

Patch:
diff --git a/crates/gen-wasmtime/src/lib.rs b/crates/gen-wasmtime/src/lib.rs
index 7466678cc..39763e735 100644
--- a/crates/gen-wasmtime/src/lib.rs
+++ b/crates/gen-wasmtime/src/lib.rs
@@ -882,7 +882,7 @@ impl Generator for Wasmtime {
     fn finish(&mut self, iface: &Interface, files: &mut Files) {
         for (module, funcs) in sorted_iter(&self.imports) {
             let module_camel = module.to_camel_case();
-            let is_async = funcs.iter().any(|f| self.opts.async_.includes(&f.name));
+            let is_async = !self.opts.async_.is_none();
             if is_async {
                 self.src.push_str("#[witx_bindgen_wasmtime::async_trait]\n");
             }
@@ -965,7 +965,7 @@ impl Generator for Wasmtime {
 
         for (module, funcs) in mem::take(&mut self.imports) {
             let module_camel = module.to_camel_case();
-            let is_async = funcs.iter().any(|f| self.opts.async_.includes(&f.name));
+            let is_async = !self.opts.async_.is_none();
             self.push_str("\npub fn add_");
             self.push_str(&module);
             self.push_str("_to_linker<T, U>(linker: &mut wasmtime::Linker<T>");


Test patch:
diff --git a/crates/gen-wasmtime/tests/run.rs b/crates/gen-wasmtime/tests/run.rs
index 275ba4275..9463fe891 100644
--- a/crates/gen-wasmtime/tests/run.rs
+++ b/crates/gen-wasmtime/tests/run.rs
@@ -78,6 +78,16 @@ mod async_tests {
             async: ["bar"],
         });
     }
+    mod resource_with_none_async {
+        witx_bindgen_wasmtime::import!({
+            src["x"]: "
+                resource y {
+                    z: function() -> string
+                }
+            ",
+            async: [],
+        });
+    }
 }
 
 mod custom_errors {