Cannot infer an appropriate lifetime for autoref due to conflicting requirements

Solution 1:

Here's a smaller example that reproduces the problem:

struct FontLoader(String);
struct Font<'a>(&'a str);

impl FontLoader {
    fn load(&self) -> Font {
        Font(&self.0)
    }
}

struct Window;

struct Phi<'window> {
    window: &'window Window,
    loader: FontLoader,
    font: Option<Font<'window>>,
}

impl<'window> Phi<'window> {
    fn do_the_thing(&mut self) {
        let font = self.loader.load();
        self.font = Some(font);
    }
}

fn main() {}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:20:32
   |
20 |         let font = self.loader.load();
   |                                ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 |     fn do_the_thing(&mut self) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:20:20
   |
20 |         let font = self.loader.load();
   |                    ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'window` as defined on the impl at 18:6...
  --> src/main.rs:18:6
   |
18 | impl<'window> Phi<'window> {
   |      ^^^^^^^
note: ...so that the expression is assignable
  --> src/main.rs:21:21
   |
21 |         self.font = Some(font);
   |                     ^^^^^^^^^^
   = note: expected `Option<Font<'window>>`
              found `Option<Font<'_>>`

The problem is indeed that you have constructed an impossible case. Specifically, the code states these points:

  1. Phi is going to include a reference to a Window. That referred-to value lives for the lifetime 'window.

  2. Phi is going to include a Font, which contains a reference. That referred-to value lives for the lifetime 'window.

  3. FontLoader returns a Font which contains a reference to a value with the lifetime of the loader. This is due to lifetime inference, which when expanded looks like:

    impl FontLoader {
        fn load<'a>(&'a self) -> Font<'a> {
            Font(&self.0)
        }
    }
    

    I highly encourage adding #![deny(rust_2018_idioms)] to your crate, which will disallow this specific type of lifetime inference.

Then the code attempts to load a Font from the FontLoader in Phi, which does not have the lifetime 'window and store that Font into Phi. FontLoader (and thus Font) does not live long enough, so it cannot be stored in Phi.

The compiler has correctly prevented incorrect code.


Your next attempt would probably be to introduce a second lifetime:

struct Phi<'window, 'font> {
    window: &'window Window,
    loader: FontLoader,
    font: Option<Font<'font>>,
}

impl<'window, 'font> Phi<'window, 'font> {
    fn do_the_thing(&'font mut self) {
        let font = self.loader.load();
        self.font = Some(font);
    }
}

This will actually compile, but probably doesn't do what you want. See Why can't I store a value and a reference to that value in the same struct? for further information.

More likely, you want to take a reference to the font loader:

struct Phi<'a> {
    window: &'a Window,
    loader: &'a FontLoader,
    font: Option<Font<'a>>,
}

impl<'a> Phi<'a> {
    fn do_the_thing(&mut self) {
        let font = self.loader.load();
        self.font = Some(font);
    }
}

Here, I've renamed the lifetime as it isn't strictly for the window anymore.