If you use await!(some_fut) inside an arm of a match X, the generated future eagerly borrows the value of X, if it not needed.
This may not usually be noticeable, but the issue compounds when the type X contains a trait object, and the future you wish to return is impl Future + Send. This causes a misleading error message that "dyn Trait + Send cannot be shared between threads", which is required to for &X: Send.
Example
Here's a simple struct with a trait object:
struct Client(Box<Any + Send>);
Consider a function like this:
impl Client {
fn status(&self) -> u16 {
200
}
}
You could consider using a match to determine what kind of future to await (or what arguments to pass):
async fn get() {
}
pub fn wat() -> impl Future + Send {
let client = Client(Box::new(true));
async move {
match client.status() {
200 => {
let _x = await!(get());
},
_ => (),
}
}
}
If the await is moved out of the match block, all is well:
pub fn ok() -> impl Future + Send {
let client = Client(Box::new(true));
async move {
if client.status() == 200 {
let _x = await!(get());
}
}
}
The wat function causes this compilation error:
error[E0277]: `(dyn std::any::Any + std::marker::Send + 'static)` cannot be shared between threads safely
--> src/main.rs:21:17
|
21 | pub fn wat() -> impl Future + Send {
| ^^^^^^^^^^^^^^^^^^ `(dyn std::any::Any + std::marker::Send + 'static)` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn std::any::Any + std::marker::Send + 'static)>`
= note: required because it appears within the type `std::boxed::Box<(dyn std::any::Any + std::marker::Send + 'static)>`
= note: required because it appears within the type `Client`
= note: required because of the requirements on the impl of `for<'r> std::marker::Send` for `&Client`
= note: required because it appears within the type `for<'r> {Client, &'r Client, u16, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:23:16: 30:6 client:Client for<'r> {Client, &'r Client, u16, impl std::future::Future, ()}]`
= note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:23:16: 30:6 client:Client for<'r> {Client, &'r Client, u16, impl std::future::Future, ()}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: the return type of a function must have a statically known size
Playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=2a9dbea32d31457d50d40b99c52ee214 (updated to latest syntax -Niko)
If you use
await!(some_fut)inside an arm of amatch X, the generated future eagerly borrows the value ofX, if it not needed.This may not usually be noticeable, but the issue compounds when the type
Xcontains a trait object, and the future you wish to return isimpl Future + Send. This causes a misleading error message that "dyn Trait + Sendcannot be shared between threads", which is required to for&X: Send.Example
Here's a simple struct with a trait object:
Consider a function like this:
You could consider using a match to determine what kind of future to await (or what arguments to pass):
If the
awaitis moved out of the match block, all is well:The
watfunction causes this compilation error:Playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=2a9dbea32d31457d50d40b99c52ee214 (updated to latest syntax -Niko)