Cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

Hello, I'm trying to understand lifetime subtyping, and why the compiler is complaining about my code

struct FooRef<'o> {
    pub foo_ref: &'o dyn DoesFoo<'o>,
}

struct FooRefSet<'o> {
    pub foo_refs: Vec<FooRef<'o>>,
}

trait DoesFoo<'o> {
    fn foo(&'o self, set: &mut FooRefSet<'o>);
}

struct SomeType {}
impl<'o> DoesFoo<'o> for SomeType {
    fn foo(&'o self, set: &mut FooRefSet<'o>) {
        set.foo_refs.push(FooRef { foo_ref: self })
    }
}

struct Container<'o> {
    pub foos: Vec<Box<dyn DoesFoo<'o>>>,
}
impl<'c, 'o: 'c> Container<'o> {
    fn collect_foos(&'c self, set: &mut FooRefSet<'o>) {
        for x in &self.foos {
            x.foo(set);
        }
    }
}

fn main() {
    let mut container = Container { foos: Vec::new() };
    container.foos.push(Box::new(SomeType {}));

    let mut set = FooRefSet {
        foo_refs: Vec::new(),
    };

    container.collect_foos(&mut set);
}

When I try to compile this, I receive the error:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src\main.rs:25:18
   |
25 |         for x in &self.foos {
   |                  ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'c` as defined on the impl at 23:6...
  --> src\main.rs:23:6
   |
23 | impl<'c, 'o: 'c> Container<'o> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:25:18
   |
25 |         for x in &self.foos {
   |                  ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'o` as defined on the impl at 23:10...
  --> src\main.rs:23:10
   |
23 | impl<'c, 'o: 'c> Container<'o> {
   |          ^^
note: ...so that the types are compatible
  --> src\main.rs:26:15
   |
26 |             x.foo(set);
   |               ^^^
   = note: expected  `&'o dyn DoesFoo<'o>`
              found  `&dyn DoesFoo<'o>`

Since &self in collect_foos function has a lifetime of 'c, I would assume it would be compatible with 'o, but apparently my assumption is wrong. Could anyone help shed some light on why this doesn't work as I'm expecting? Thank you!

As I understand it, you are confused as to why &mut FooRefSet<'o> can't be converted into &mut FooRefSet<'c> when 'c is a shorter lifetime?

Well basically, if you could perform that conversion, you would be able to override the value behind the mutable reference with a FooRefSet<'c>. But once you get back outside this function, the variable that you got the mutable reference from would now contain a FooRefSet<'c> even though the type of that variable requires a value of the longer lifetime FooRefSet<'o>.

You can read more in the variance chapter in the nomicon.

1 Like

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