Compiler cannot infer an appropriate lifetime

My code got a lifetime issue and I struggled for days and still can't solve it, here's a minimum reproducible code:

pub fn run<F>(f: F) -> ! where F: 'static + FnMut(), {
    loop {
        f();
    }
}

struct Bar {}

struct Foo<'a> {
    bar: Option<&'a Bar>,
}

impl<'a> Foo<'a> {
    pub fn new_foo() -> Self {
        Foo { bar: None }
    }
    pub fn add_bar(&mut self, bar: &'a Bar) {
        self.bar = Some(bar);
    }
}

fn main() {
    let mut foo = Foo::new_foo();
    let bar = Bar {};
    run(move || {
        foo.add_bar(&bar);
    })
}

The idea is that new_foo() is very expensive in my case, so I want to create it first, instead of create in the closure, since run() will run the closure again and again.

But the compiler failed to compile:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:23:21
   |
23 |         foo.add_bar(&bar);
   |                     ^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
  --> src/main.rs:22:9
   |
22 |     run(move || {
   |         ^^^^^^^
note: ...so that closure can access `bar`
  --> src/main.rs:23:21
   |
23 |         foo.add_bar(&bar);
   |                     ^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:22:9: 24:6]` will meet its required lifetime bounds...
  --> src/main.rs:22:5
   |
22 |     run(move || {
   |     ^^^
note: ...that is required by this bound
  --> src/main.rs:1:35
   |
1  | pub fn run<F>(f: F) -> ! where F: 'static + FnMut(), {
   |                                   ^^^^^^^

I'm always afraid of lifetime errors, but lucky thing is that compiler will give me suggestions in most time, but not for this one.

The run() function is a public API which cannot be changed, so how can I write the right code, so my design can work as I expected?

foo and bar are both moved into the closure. foo.add_bar(&bar) would need to turn the closure into a self-referential struct (since it places a reference to bar in to foo) which can’t work.

Interestingly, (presumably due to NLL) the error message is a lot shorter on nightly. Edit: Ah, the error message on nightly is about the same you get for this code on stable if you try compiling without that F: 'static bound.

2 Likes

The shorter message seems clearer, but I still can't found a solution, is there any way to only change codes in main() (or may be add_bar()) to accomplish my goal?

And whenever I meet some problems with closure, I always turn it to a struct for debugging. In this case, does

move || {
        foo.add_bar(&bar);
    }

the same with

pub struct TheClosure<'a> {
    foo: Foo<'a>,
    bar: Bar,
}

impl<'a> TheClosure<'a> {
    pub fn run(&'a mut self) {
        loop {
            self.foo.add_bar(&self.bar);
        }
    }
}

?

It's more like

impl<'a> TheClosure<'a> {
    pub fn run_once(&mut self) {
        self.foo.add_bar(&self.bar);
    }

    pub fn run(&mut self) {
        loop {
            self.run_once();
        }
    }
}

And you can try that to see it doesn't work.

Note that this compiles:

impl<'a> TheClosure<'a> {
    pub fn run_once(&'a mut self /* == &'a mut TheClosure<'a> */) {
        self.foo.add_bar(&self.bar);
    }
}

but calling that function requires exclusively borrowing TheClosure for the rest of its lifetime; after that borrow, it's only usable through the &mut, which is no longer available after the call and thus you can't actually call run_once again. This is, in fact, a way to create a self-referential (with &s) struct in safe Rust. It just has extremely niche utility. If you add back run for example, the multiple calls implied by the loop will give you an error. Your version with the loop inside run compiled only because it is a variation on run_once here.

And that's all moot in this case because calling the actual closure doesn't take a &'a mut self for some outside lifetime 'a anyway.

Self-referentiality aside, if you capture a Foo<'a>, you're not going to satisfy a 'static bound.

2 Likes

Does run really run forever? You could leak the Bar to create a &'static Bar and capture the &'static Bar and a Foo<'static>.

Playground.

2 Likes

That's also a confusion of mine, I don't understand why the interface add a 'static bound. The real API is the winit crate, and it said:

    /// Hijacks the calling thread and initializes the winit event loop with the provided
    /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to
    /// access any data from the calling context.
    ///
    /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
    /// event loop's behavior.
    ///
    /// Any values not passed to this function will *not* be dropped.
    ///
    /// [`ControlFlow`]: crate::event_loop::ControlFlow
    #[inline]
    pub fn run<F>(self, event_handler: F) -> !
    where
        F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
    {
        self.event_loop.run(event_handler)
    }

It doesn't explain why 'static is needed.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.