xr2nn5mobkd
xr2nn5mobkd

Reputation: 43

Rust: "returning this value requires that `'op` must outlive `'static`" with HRTB in closure returning future

Consider the following minimal example:

type Task<'a> = Box<dyn std::future::Future<Output = ()> + 'a>;

type Context<'s> = &'s str;

trait MyTrait {
    fn compute<'a>(&'a self, ctx: Context<'a>) -> Task<'a>
    where
        Self: 'a;
}

impl<F: for<'b> Fn(Context<'b>) -> Task<'b>> MyTrait for F {
    fn compute<'a>(&'a self, ctx: Context<'a>) -> Task<'a>
    where
        Self: 'a,
    {
        (self)(ctx)
    }
}

fn bla<'op>(input: &'op usize) -> impl MyTrait + 'op {
    let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
        Box::new(async move {
            println!("{}", &ctx[*input..]);
            ()
        })
    });
    v
}

The compiler generated error message is:

error: lifetime may not live long enough
  --> src/main.rs:22:9
   |
20 |   fn bla<'op>(input: &'op usize) -> impl MyTrait + 'op {
   |          --- lifetime `'op` defined here
21 |       let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
22 | /         Box::new(async move {
23 | |             println!("{}", &ctx[*input..]);
24 | |             ()
25 | |         })
   | |__________^ returning this value requires that `'op` must outlive `'static`

I don't understand why 'op must outlive 'static. The lifetime of the returned Task is bound by 'b which in turn is shorter than the Self of the boxed closure, and thus of 'op.

I also tried to model the lifetime of the trait object more explicitly, but got the same error message from this:

type Task<'a> = Box<dyn std::future::Future<Output = ()> + 'a>;

type Context<'s> = &'s str;

trait MyTrait<'l> {
    fn compute<'a>(&'l self, ctx: Context<'a>) -> Task<'l>
    where
        'l: 'a;
}

impl<'c, F: 'c + for<'b> Fn(Context<'b>) -> Task<'b>> MyTrait<'c> for F {
    fn compute<'a>(&'c self, ctx: Context<'a>) -> Task<'c>
    where
        'c: 'a,
    {
        (self)(ctx)
    }
}

fn bla<'op>(input: &'op usize) -> impl MyTrait<'op> + 'op {
    let v: Box<dyn for<'b> Fn(Context<'b>) -> Task<'b> + 'op> = Box::new(move |ctx| {
        Box::new(async move {
            println!("{}", &ctx[*input..]);
            ()
        })
    });
    v
}

Edit: I guess another more open way of asking this question would be: How to I constrain the lifetime of a HRTB by an outer lifetime?

Upvotes: 1

Views: 277

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71340

I don't understand why 'op must outlive 'static. The lifetime of the returned Task is bound by 'b which in turn is shorter than the Self of the boxed closure, and thus of 'op.

Who said? The only thing the compiler knows about it is that it is required to be true for any lifetime (HRTB). Any lifetime includes 'static, and therefore the compiler requires 'op: 'b which implies 'op: 'static.

Upvotes: 1

Related Questions