Sharing higher-rank trait bound lifetimes between bounds

Hi, I have a question about sharing higher-rank trait bound lifetimes between two bounds.

I wrote this function:

async fn calc<T, TFut, F>(action: F) -> T
where
    TFut: Future<Output = T>,
    F: FnOnce(&mut i32) -> TFut,
{
    let mut num = 42;
    action(&mut num).await
}

It compiles just fine, but when it is called and num is used in the closure, it fails:

async fn run() {
    let result = calc(|num| async move {
        *num
    }).await;

    println!("{:?}", result);
}
error message
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:11:40
   |
11 |       let result = calc(|num| async move {
   |  ________________________________________^
12 | |         *num
13 | |     }).await;
   | |_____^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 11:23...
  --> src/main.rs:11:23
   |
11 |       let result = calc(|num| async move {
   |  _______________________^
12 | |         *num
13 | |     }).await;
   | |_____^
note: ...so that the types are compatible
  --> src/main.rs:11:40
   |
11 |       let result = calc(|num| async move {
   |  ________________________________________^
12 | |         *num
13 | |     }).await;
   | |_____^
   = note: expected  `&mut i32`
              found  `&mut i32`
note: but, the lifetime must be valid for the call at 11:18...
  --> src/main.rs:11:18
   |
11 |       let result = calc(|num| async move {
   |  __________________^
12 | |         *num
13 | |     }).await;
   | |______^
note: ...so type `impl core::future::future::Future` of expression is valid during the expression
  --> src/main.rs:11:18
   |
11 |       let result = calc(|num| async move {
   |  __________________^
12 | |         *num
13 | |     }).await;
   | |______^

I understand that this happens, because the Future returned by the closure may outlive the num.

In order to fix this, I'd like to specify something like this to communicate in the function
signature that num always outlives the Future:

async fn calc<T, TFut, F>(action: F) -> T
where
    TFut: Future<Output = T> + 'lifetime,
    F: FnOnce(&'lifetime mut i32) -> TFut,
{
    let mut num = 42;
    action(&mut num).await
}

However I don't know where to define 'lifetime. If I define it on either one of the bounds, it
cannot be referenced on the other one:

async fn calc<T, TFut, F>(action: F) -> T
where
    for <'lifetime> TFut: Future<Output = T> + 'lifetime,
    F: FnOnce(&'lifetime mut i32) -> TFut,
{
    let mut num = 42;
    action(&mut num).await
}
error message
error[E0261]: use of undeclared lifetime name `'lifetime`
  --> src/main.rs:21:16
   |
21 |     F: FnOnce(&'lifetime mut i32) -> TFut,
   |                ^^^^^^^^^ undeclared lifetime
   |
   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider introducing lifetime `'lifetime` here
   |
18 | async fn calc<'lifetime, T, TFut, F>(action: F) -> T
   |               ^^^^^^^^^^
help: consider making the bound lifetime-generic with a new `'lifetime` lifetime
   |
21 |     F: for<'lifetime> FnOnce(&'lifetime mut i32) -> TFut,
   |        ^^^^^^^^^^^^^^

So my question is this:

Is there a way to specify 'lifetime like above and make this function work?

At a glance, this looks similar to this recent question:

You are correct, it is pretty much the exact same question. I did not find that one in my search.

So it seems as though there is no way to specify that lifetime. Thank you anyway for your time.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.