Description
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)
Metadata
Metadata
Assignees
Labels
Type
Projects
Status