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 is unnecessarily captured in nested functions returning impl trait via async #63032

Open
sfackler opened this issue Jul 27, 2019 · 5 comments
Labels
A-async-await Area: Async & Await A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. 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.

Comments

@sfackler
Copy link
Member

When trying to create some futures that do a bit of work up-front to avoid borrowing some inputs, I ran into this strange issue where it seems like an input lifetime is being unnecessarily captured by the returned impl trait even though the value isn't:

#![feature(async_await)]
use std::future::Future;

fn query<'a, I>(params: I) -> impl Future<Output = Vec<i32>> + 'static
where
    I: IntoIterator<Item = &'a i32>,
{
    let start = start(params);
    
    async {
        start.await
    }
}

fn start<'a, I>(params: I) -> impl Future<Output = Vec<i32>> + 'static
where
    I: IntoIterator<Item = &'a i32>,
{
    let buf = encode(params);
    
    async {
        buf
    }
}

fn encode<'a, I>(params: I) -> Vec<i32>
where
    I: IntoIterator<Item = &'a i32>,
{
    params.into_iter().cloned().collect()
}
error[E0310]: the parameter type `I` may not live long enough
 --> src/lib.rs:4:31
  |
4 | fn query<'a, I>(params: I) -> impl Future<Output = Vec<i32>> + 'static
  |              -                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |              |
  |              help: consider adding an explicit lifetime bound `I: 'static`...
  |
note: ...so that the type `impl std::future::Future` will meet its required lifetime bounds
 --> src/lib.rs:4:31
  |
4 | fn query<'a, I>(params: I) -> impl Future<Output = Vec<i32>> + 'static
  |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0310`.

It also seems really weird that this only happens with 2 layers of "nesting" - start compiles just fine, but query doesn't even though it's pretty much just a pass-through.

@sfackler sfackler added the A-async-await Area: Async & Await label Jul 27, 2019
@nikomatsakis nikomatsakis added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 13, 2019
@nikomatsakis nikomatsakis self-assigned this Aug 13, 2019
@nikomatsakis nikomatsakis added the AsyncAwait-Polish Async-await issues that are part of the "polish" area label Aug 13, 2019
@nikomatsakis
Copy link
Contributor

Check-in from async-await foundations wg: marking as blocking for now and self-assigning to do a bit of investigation. Not entirely sure what's going on.

@nikomatsakis
Copy link
Contributor

OK, so, first of all -- removing the + 'static bound (which is not necessary) makes the code compile.

@nikomatsakis
Copy link
Contributor

I think that this bug is a duplicate of #42940. What happens is that the return type of start is something like Opaque<I> -- i.e., it captures all the type parameters from the calling function. Now, we know that type Opaque<I> = impl Future<Output=Vec<i32>> + 'static, so it ought to compile, but because of #42940, we wind up requiring that I: 'static in order to compile.

@nikomatsakis nikomatsakis added A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. AsyncAwait-Triaged Async-await issues that have been triaged during a working group meeting. and removed AsyncAwait-Polish Async-await issues that are part of the "polish" area labels Aug 14, 2019
@nikomatsakis
Copy link
Contributor

As this is a duplicate of #42940, it doesn't need to block stabilization. In particular, I believe that improving our ability to figure out that the type is 'static would be forwards compatible -- also, this is really a bug about impl Trait, more than async itself.

@nikomatsakis nikomatsakis removed their assignment Oct 9, 2019
@steveklabnik
Copy link
Member

Triage: to get this to compile on stable, you only need to remove the feature flag, the code still "works." It fails to compile, and removing 'static lets it still compile.

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-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. 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.
Projects
None yet
Development

No branches or pull requests

5 participants