Compiler error message with async function


#1

I’ve come across an odd compile error that seems to have something to do with async code generation. This is using the nightly compiler (719b0d984 2019-03-13) and I’ve tried to put together a minimal example below. The root of the problem is in the Y::foo function, which as written requires Y: Sync in order for the returned future to be Send . The interesting thing is that if we capture the result of Y::get_value() in a local variable the problem goes away. Presumably the issue is that &self is being borrowed across a yield point, and therefore needs to be Sync in case it gets resumed on a different thread. But I’m a bit unclear on why the destructuring let causes a reference to be held across the yield point (if this is indeed what’s going on). Also wondering if it’s possible to improve the error message for this to make it easier to debug!

#![feature(futures_api)]
#![feature(optin_builtin_traits)]
#![feature(await_macro)]
#![feature(async_await)]

use std::pin::Pin;
use std::future::Future;
use std::task::{Waker, Poll};

struct F;
impl Future for F {
    type Output = ();
    fn poll(self: Pin<&mut Self>, _: &Waker) -> Poll<()> {
        Poll::Pending
    }
}

struct Y;

unsafe impl Send for Y {}
impl !Sync for Y {}

impl Y {
    pub async fn foo(&mut self) {
        let value = self.get_value();
        if let Some(_) = self.get_value() { // <--- THIS LINE CAUSES A COMPILE ERROR
// But this compiles fine:
//      if let Some(_) = value {                                            
            await!(F {});
        }
    }

    fn get_value(&self) -> Option<u32> {
        None
    }
}

fn execute(_: impl Future<Output=()> + Send) {
    
}

fn main() {
    let mut y = Y {};
    execute(y.foo());
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: `Y` cannot be shared between threads safely
  --> src/main.rs:42:5
   |
42 |     execute(y.foo());
   |     ^^^^^^^ `Y` cannot be shared between threads safely
   |
   = help: the trait `std::marker::Sync` is not implemented for `Y`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&Y`
   = note: required because it appears within the type `for<'r, 's> {std::option::Option<u32>, &'r mut Y, Y, &'s Y, F, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:24:33: 29:6 self:&mut Y for<'r, 's> {std::option::Option<u32>, &'r mut Y, Y, &'s Y, F, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:24:33: 29:6 self:&mut Y for<'r, 's> {std::option::Option<u32>, &'r mut Y, Y, &'s Y, F, ()}]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `impl std::future::Future`
note: required by `execute`
  --> src/main.rs:36:1
   |
36 | fn execute(_: impl Future<Output=()> + Send) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.