Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lifetime error when Send is enforced on async function return type #64176

Open
tomaka opened this issue Sep 5, 2019 · 1 comment

Comments

@tomaka
Copy link
Contributor

commented Sep 5, 2019

Just like a lot of lifetime issues, I'm not actually sure whether this is a bug in the compiler or a bug in my code.

The following code:

use std::pin::Pin;
use std::future::Future;

trait FooRef<'a> {
    type Elem;
    fn next_elem(self) -> Pin<Box<dyn Future<Output = Self::Elem> + Send + Sync + 'a>>;
}

struct FooImpl;
impl<'a> FooRef<'a> for &'a mut FooImpl {
    type Elem = &'a mut FooImpl;
    fn next_elem(self) -> Pin<Box<dyn Future<Output = Self::Elem> + Send + Sync + 'a>> {
        Box::pin(async move { self })
    }
}


async fn run<F>(mut foo: F)
    where for<'r> &'r mut F: FooRef<'r>
{
    loop {
        foo.next_elem().await;
    }
}


fn test() {
    fn req<T: Send>(_: T) {}
    req(run(FooImpl))
}

Triggers the following compilation error:

error: implementation of `FooRef` is not general enough
  --> src/lib.rs:29:5
   |
29 |     req(run(FooImpl))
   |     ^^^
   |
   = note: `FooRef<'1>` would have to be implemented for the type `&'0 mut FooImpl`, for any two lifetimes `'0` and `'1`
   = note: but `FooRef<'2>` is actually implemented for the type `&'2 mut FooImpl`, for some specific lifetime `'2`

Replacing T: Send with just T makes it compile fine.

Replacing async fn run<F>(mut foo: F) with async fn run(mut foo: FooImpl) (ie. removing the generic parameter) also works fine.

Code explanation: calling foo.next_elem() return a Future that should keep foo borrowed, and produces an element (type Elem;) that still keeps foo borrowed.

I don't really see the relationship between this behaviour and Send. All the types used in this code do implement Send.

My compiler version is rustc 1.39.0-nightly (c6e9c76c5 2019-09-04).

@pustaczek

This comment has been minimized.

Copy link

commented Sep 11, 2019

I also ran into this while trying to rewrite one of my projects. The issue does not seem to be related to lifetimes at all:

async fn once_upon_a_time() {
    let _doggy = Bad { friend: () };
    async {}.await;
}

fn control() {
    enforce(once_upon_a_time());
}
fn enforce(_: impl Send) {}

type Bad = GenericBad<dyn LaserDoggy>;
struct GenericBad<T: Doggy+?Sized> {
    friend: <T as Doggy>::Friend,
}

trait Doggy {
    type Friend;
}
trait LaserDoggy {}
impl Doggy for dyn LaserDoggy {
    type Friend = ();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.