Skip to content

async fn doesn't capture lifetimes of type parameters if other lifetimes are present #55324

Closed
@cramertj

Description

@cramertj

This doesn't compile:

async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
    let y = await!(future);
    *x + y
}
error[E0311]: the parameter type `F` may not live long enough
 --> src/lib.rs:5:62
  |
5 | async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
  |                                                              ^^^
  |
  = help: consider adding an explicit lifetime bound for `F`
note: the parameter type `F` must be valid for the anonymous lifetime #1 defined on the function body at 5:1...
 --> src/lib.rs:5:1
  |
5 | / async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
6 | |     let y = await!(future);
7 | |     *x + y
8 | | }
  | |_^
note: ...so that the type `impl std::future::Future` will meet its required lifetime bounds
 --> src/lib.rs:5:62
  |
5 | async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
  |                                                              ^^^

But it does compile if you replace the &i32 with an i32. This is because async fn foo<T>() -> R desugars to -> impl Future<Output = R>, but async fn foo<T>(x: &i32) -> R desugars to -> impl Future<Output = R> + '_. Since T doesn't outlive the elided lifetime, it fails to compile. We need instead to capture the minimum lifetime of T and '_. Note that this is similar to the issue where async fn cannot have multiple different named lifetimes because there's not a way to express the desugared "minimum of all lifetimes" in the -> impl Trait return type.

cc @withoutboats who originally reported this on discord.

Metadata

Metadata

Assignees

Labels

A-async-awaitArea: Async & AwaitA-lifetimesArea: Lifetimes / regionsAsyncAwait-PolishAsync-await issues that are part of the "polish" area

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions