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

"expected bound lifetime parameter, found concrete lifetime" when passing a 'static reference to a closure that returns a future #68521

Open
shepmaster opened this issue Jan 24, 2020 · 1 comment
Labels
A-async-await A-closures A-diagnostics A-lifetimes AsyncAwait-Triaged C-bug P-medium T-compiler

Comments

@shepmaster
Copy link
Member

@shepmaster shepmaster commented Jan 24, 2020

use std::future::Future;

fn main() {
    let _ = wrapper(hello);
}

static GLOBAL: i32 = 42;

async fn wrapper<F, FutResp>(f: F)
where
    F: Fn(&i32) -> FutResp,
    FutResp: Future<Output = ()>,
{
    f(&GLOBAL).await
}

async fn hello(_: &i32) {
    println!("Hello");
}

(Playground)

Errors:

error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(&i32) -> impl std::future::Future {hello} as std::ops::FnOnce<(&'r i32,)>>::Output == _`
  --> src/main.rs:4:13
   |
4  |     let _ = wrapper(hello);
   |             ^^^^^^^ expected bound lifetime parameter, found concrete lifetime
...
9  | async fn wrapper<F, FutResp>(f: F)
   |          -------
10 | where
11 |     F: Fn(&i32) -> FutResp,
   |                    ------- required by this bound in `wrapper`

I can make the code work by restricting the closure to only accept 'static references:

async fn wrapper<F, FutResp>(f: F)
where
    F: Fn(&'static i32) -> FutResp,
    //     ^^^^^^^
    FutResp: Future<Output = ()>,

I did try to add 'static bounds to the response future (and the closure, for good measure), but this did not help:

async fn wrapper<F, FutResp>(f: F)
where
    F: Fn(&i32) -> FutResp + 'static,
    FutResp: Future<Output = ()> + 'static,

The equivalent(?) synchronous code works as I'd expect:

fn main() {
    let _ = wrapper(hello);
}

static GLOBAL: i32 = 42;

fn wrapper<F>(f: F)
where
    F: Fn(&i32) -> (),
{
    f(&GLOBAL)
}

fn hello(_: &i32) {
    println!("Hello");
}
@jonas-schievink jonas-schievink added A-async-await A-closures A-lifetimes C-bug T-compiler labels Jan 24, 2020
@Aaron1011
Copy link
Member

@Aaron1011 Aaron1011 commented Jan 25, 2020

Adding an explicit lifetime 'a allows this to compile:

use std::future::Future;

fn main() {
    let _ = wrapper(hello);
}

static GLOBAL: i32 = 42;

async fn wrapper<'a, F, FutResp>(f: F)
where
    F: Fn(&'a i32) -> FutResp + 'a,
    FutResp: Future<Output = ()>,
{
    f(&GLOBAL).await
}

async fn hello(_: &i32) {
    println!("Hello");
}

I think the issue is that F: Fn(&i32) -> FutResp requires FutResp to be 'static (or at least, not dependent on the lifetime of the &i32. However, the future returned by async fn hello(_: &i32) does depend on the lifetime of the &i32, since the &i32 can be used within the generator.

However, the error message is almost completely opaque. We should probably add some special-casing around lifetime-related errors when async functions are involved.

@jonas-schievink jonas-schievink added the A-diagnostics label Jan 25, 2020
@tmandry tmandry added AsyncAwait-OnDeck AsyncAwait-Triaged labels Jan 28, 2020
@tmandry tmandry added this to To do in wg-async work Feb 11, 2020
@tmandry tmandry added the P-medium label Mar 3, 2020
@tmandry tmandry removed this from To do in wg-async work Mar 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await A-closures A-diagnostics A-lifetimes AsyncAwait-Triaged C-bug P-medium T-compiler
Projects
None yet
Development

No branches or pull requests

4 participants