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 · 4 comments

Comments

@sfackler
Copy link
Member

commented Jul 27, 2019

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.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

commented Aug 13, 2019

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

This comment has been minimized.

Copy link
Contributor

commented Aug 14, 2019

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

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

commented Aug 14, 2019

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

This comment has been minimized.

Copy link
Contributor

commented Aug 14, 2019

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.

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.