Skip to content

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

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

Closed
tomaka opened this issue Sep 5, 2019 · 3 comments
Closed

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

tomaka opened this issue Sep 5, 2019 · 3 comments
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@tomaka
Copy link
Contributor

tomaka 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).

@Centril Centril added A-async-await Area: Async & Await AsyncAwait-Unclear T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Sep 5, 2019
@unneon
Copy link

unneon 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 = ();
}

@nikomatsakis
Copy link
Contributor

Quite likely related to #64552

@cramertj cramertj added AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. and removed AsyncAwait-Unclear labels Sep 24, 2019
@dtolnay
Copy link
Member

dtolnay commented Feb 25, 2020

Closing in favor of #64552 which is the same issue but has a bit more investigation in the thread.

@dtolnay dtolnay closed this as completed Feb 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants