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

Unexpected "the parameter type X may not live long enough" error in asynchronous functions #95719

Open
wvwwvwwv opened this issue Apr 6, 2022 · 4 comments
Labels
A-async-await Area: Async & Await A-GATs Area: Generic associated types (GATs) A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. WG-async Working group: Async & await

Comments

@wvwwvwwv
Copy link

wvwwvwwv commented Apr 6, 2022

When a Future is wrapped in an async block or an async function, some of its traits are lost, e.g., Send, thus causing various issues.

I tried this code:

#![feature(impl_trait_in_assoc_type)]

use std::future::Future;

pub trait Get: Send + Sync {
    type Ret<'a>: Future<Output = usize> + Send + 'a
    where
        Self: 'a;
    fn get<'a>(&'a self) -> Self::Ret<'a>
    where
        Self: 'a;
}

impl Get for usize {
    type Ret<'a> = impl Future<Output = usize> + Send + 'a
    where
        Self: 'a;

    fn get<'a>(&'a self) -> Self::Ret<'a>
    where
        Self: 'a,
    {
        async move { *self }
    }
}

fn is_send<R, F: Future<Output = R> + Send>(_f: &F) -> bool {
    true
}

async fn wrap<G: Get>(g: &G) -> usize {
    let fut = g.get();
    assert!(is_send(&fut));
    fut.await
}

async fn wrap_wrap<G: Get>(g: &G) -> usize {
    let fut = wrap(g);
    assert!(is_send(&fut)); //~ ERROR the parameter type `G` may not live long enough
    fut.await
}

I expected to see no compiler errors: the returned Future from async fn wrap should be Send, because g.get() is Send and async fn wrap only wraps the code in an asynchronous code block.

Instead, this happened: the returned Future from async fn wrap is not anymore Send. Note that the error manifests differently if another lifetime bounds are involved in the trait - lifetime bound not satisfied when asserting is_send(&fut). It's even strange to see lifetime bounds or may not live long enough errors when checking the Send bound.

Meta

rustc --version --verbose:

rustc 1.59.0 (9d1b2106e 2022-02-23)
binary: rustc
commit-hash: 9d1b2106e23b1abd32fce1f17267604a5102f57a
commit-date: 2022-02-23
host: aarch64-apple-darwin
release: 1.59.0
LLVM version: 13.0.0
Error

error[E0311]: the parameter type `G` may not live long enough
   --> tests/test.rs:687:17
    |
684 |     async fn wrap_wrap<G: Get>(g: &G) -> usize {
    |                        -- help: consider adding an explicit lifetime bound...: `G: 'a +`
...
687 |         assert!(is_send(&fut));
    |                 ^^^^^^^ ...so that the type `G` will meet its required lifetime bounds...
    |
note: ...that is required by this bound
   --> tests/test.rs:674:43
    |
674 |     fn is_send<R, F: Future<Output = R> + Send>(_f: &F) -> bool {
    |                                           ^^^^

error: could not compile `async-trait` due to previous error

@wvwwvwwv wvwwvwwv added the C-bug Category: This is a bug. label Apr 6, 2022
@wvwwvwwv wvwwvwwv changed the title Unexpected "the parameter type X may not live long enough" in asynchronous functions Unexpected "the parameter type X may not live long enough" error in asynchronous functions Apr 6, 2022
@wvwwvwwv
Copy link
Author

Now, I understand that the code should not compile since g.get() borrows data from the stack of wrap, thus the returned impl Future is not Send. However, the error message is still weird...

@wvwwvwwv
Copy link
Author

Also, wouldn't it be weird?

async move {
    let fut = g.get();
    assert!(is_send(&fut));
    fut.await
}

I understand that the above code block is !Send because the closure captures &self reference which is local to the stack, but since the code block is asynchronous, it is guaranteed that the value of &self is only evaluated once the async move block is pinned, and therefore the code block can actually be sent!

@ivan770
Copy link

ivan770 commented Jun 5, 2022

This issue is probably related to #90696, since I was able to run your code by adding for<'a> <G as Get>::Ret<'a>: Send + Sync bound: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6827058de35474e1afc64733741d95f7

@fmease fmease added A-trait-system Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. F-associated_type_bounds `#![feature(associated_type_bounds)]` F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs T-types Relevant to the types team, which will review and decide on the PR/issue. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` A-lifetimes Area: Lifetimes / regions A-async-await Area: Async & Await and removed needs-triage-legacy labels Jan 25, 2024
@compiler-errors compiler-errors removed the F-associated_type_bounds `#![feature(associated_type_bounds)]` label Feb 21, 2024
@traviscross
Copy link
Contributor

@rustbot labels +AsyncAwait-Triaged +WG-async

We reviewed this today in WG-async triage.

We believe this is a manifestation of what's being worked on and tracked in #110338.

@rustbot rustbot added AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. WG-async Working group: Async & await labels Feb 26, 2024
@fmease fmease added A-GATs Area: Generic associated types (GATs) and removed C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs labels Sep 24, 2024
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 A-GATs Area: Generic associated types (GATs) A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. WG-async Working group: Async & await
Projects
None yet
Development

No branches or pull requests

7 participants