Stream: git-wasmtime

Topic: wasmtime / issue #11752 `bindgen!` doesn't add `Send` bou...


view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 13:36):

anlavandier edited issue #11752:

Test Case

Wit file:

package example:example;

interface api {
    foo: func();
}

world bar {
    import api;
    export baz: func();
}

world api-impl {
    import api;
}

rust code:

use wasmtime::component::bindgen;

use crate::async_impl::MyHost;

bindgen!({
    world: "bar",
    path: "wit/example.wit",
    with: {
        "example:example/api": async_impl,
    },
    imports: {
        default: async,
    }
});

pub mod async_impl {
    use wasmtime::component::bindgen;
    bindgen!({
        world: "api-impl",
        path: "wit/example.wit",
        imports: {
            default: async,
        }
    });

    pub struct MyHost;


    pub use example::example::api::{Host, HostWithStore, add_to_linker};

    impl Host for MyHost {
        async fn foo(&mut self) {
            let _ = 3 + 4;
        }
    }
}
fn main() {}

Expected results

The above code should compile

Observed results

the following compile error:

error[E0277]: `T` cannot be sent between threads safely
  --> src/main.rs:3:1
   |
3  | / bindgen!({
4  | |     world: "bar",
5  | |     path: "wit/example.wit",
6  | |     with: {
...  |
12 | | });
   | |__^ `T` cannot be sent between threads safely
   |
note: required by a bound in `add_to_linker`
  --> src/main.rs:16:5
   |
16 | /     bindgen!({
17 | |         world: "api-impl",
18 | |         path: "wit/example.wit",
19 | |         imports: {
...  |
22 | |     });
   | |______^ required by this bound in `add_to_linker`
   = note: this error originates in the macro `bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting type parameter `T` with trait `Send`
   |
12 | }), T: std::marker::Send;
   |   ++++++++++++++++++++++

Wasmtime version or commit:
wasmtime = { version ="37.0.1", default-features = false, features = ["runtime", "component-model", "async", "std"] }

Operating system: N/A

Architecture: N/A

Extra info

Adding import foobar: func(); to the bar world and adding a corresponding implementation of BarImports for MyHost fixes this.

I believe that the bug is cause by the fact that wit_bindgen::wasmtime::world_add_to_linker relies on the presence of an async Host trait for the target world (here bar). Because the world doesn't directly import anything and relies on interfaces implemented elsewhere, no Host trait is generated and the FunctionFlags::ASYNC can't be found. Here the relevant code

Edit: I should have tested my theories before writing them in the issue. I had misread the provenance of the code. I believe that my solution is still right so I'm keeping the section as is

Potential fix

I imagine that a way to fix this would be to really on imports: {default: async} instead of the Host trait. This would introduce a (in my head) minor inconvenience which is that code that declares imports: {default: async} without actually needing it (because all of the interfaces that they import don't use async and they don't declare any "local" imports) will end up with an extraneous Send bounds but that feels like bad coding on the authors part and should not be supported imo.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 01 2025 at 14:39):

alexcrichton closed issue #11752:

Test Case

Wit file:

package example:example;

interface api {
    foo: func();
}

world bar {
    import api;
    export baz: func();
}

world api-impl {
    import api;
}

rust code:

use wasmtime::component::bindgen;

use crate::async_impl::MyHost;

bindgen!({
    world: "bar",
    path: "wit/example.wit",
    with: {
        "example:example/api": async_impl,
    },
    imports: {
        default: async,
    }
});

pub mod async_impl {
    use wasmtime::component::bindgen;
    bindgen!({
        world: "api-impl",
        path: "wit/example.wit",
        imports: {
            default: async,
        }
    });

    pub struct MyHost;


    pub use example::example::api::{Host, HostWithStore, add_to_linker};

    impl Host for MyHost {
        async fn foo(&mut self) {
            let _ = 3 + 4;
        }
    }
}
fn main() {}

Expected results

The above code should compile

Observed results

the following compile error:

error[E0277]: `T` cannot be sent between threads safely
  --> src/main.rs:3:1
   |
3  | / bindgen!({
4  | |     world: "bar",
5  | |     path: "wit/example.wit",
6  | |     with: {
...  |
12 | | });
   | |__^ `T` cannot be sent between threads safely
   |
note: required by a bound in `add_to_linker`
  --> src/main.rs:16:5
   |
16 | /     bindgen!({
17 | |         world: "api-impl",
18 | |         path: "wit/example.wit",
19 | |         imports: {
...  |
22 | |     });
   | |______^ required by this bound in `add_to_linker`
   = note: this error originates in the macro `bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting type parameter `T` with trait `Send`
   |
12 | }), T: std::marker::Send;
   |   ++++++++++++++++++++++

Wasmtime version or commit:
wasmtime = { version ="37.0.1", default-features = false, features = ["runtime", "component-model", "async", "std"] }

Operating system: N/A

Architecture: N/A

Extra info

Adding import foobar: func(); to the bar world and adding a corresponding implementation of BarImports for MyHost fixes this.

I believe that the bug is cause by the fact that wit_bindgen::wasmtime::world_add_to_linker relies on the presence of an async Host trait for the target world (here bar). Because the world doesn't directly import anything and relies on interfaces implemented elsewhere, no Host trait is generated and the FunctionFlags::ASYNC can't be found. Here the relevant code

Edit: I should have tested my theories before writing them in the issue. I had misread the provenance of the code. I believe that my solution is still right so I'm keeping the section as is

Potential fix

I imagine that a way to fix this would be to really on imports: {default: async} instead of the Host trait. This would introduce a (in my head) minor inconvenience which is that code that declares imports: {default: async} without actually needing it (because all of the interfaces that they import don't use async and they don't declare any "local" imports) will end up with an extraneous Send bounds but that feels like bad coding on the authors part and should not be supported imo.


Last updated: Dec 06 2025 at 06:05 UTC