Lifetime error in generic impl

I'm trying to implement some generic data record traits, and I hit an odd lifetime error when trying to implement a lazy-reference record type. A minimal replication is below.

I can usually figure these out, but this one has me beat. I don't see how &Lazy<impl Deref<Target=R>> can ever outlive R, or any place where I'm taking a reference to a temporary value. Randomly adding *, &, and 'a in the usual places didn't help either (unsurprisingly; there are too many options).

use std::ops::Deref;

trait Field: 'static { /* ... */ }

trait Record {
    fn try_field_ref<F:Field>(&self)->Option<&F>;
    /* Lots of default function implementations here */
}

struct Lazy<Ptr>(Ptr) where Ptr: Deref, Ptr::Target: Record;

impl<R:Record, Ptr:Deref<Target=R>> Record for Lazy<Ptr> {
    fn try_field_ref<F:Field>(&self)->Option<&F> {
        self.0.try_field_ref()
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0311]: the parameter type `R` may not live long enough
  --> src/lib.rs:14:9
   |
14 |         self.0.try_field_ref()
   |         ^^^^^^
   |
   = help: consider adding an explicit lifetime bound for `R`
note: the parameter type `R` must be valid for the anonymous lifetime #1 defined on the method body at 13:5...
  --> src/lib.rs:13:5
   |
13 | /     fn try_field_ref<F:Field>(&self)->Option<&F> {
14 | |         self.0.try_field_ref()
15 | |     }
   | |_____^
note: ...so that the type `R` is not borrowed for too long
  --> src/lib.rs:14:9
   |
14 |         self.0.try_field_ref()
   |         ^^^^^^

error[E0311]: the parameter type `R` may not live long enough
  --> src/lib.rs:14:16
   |
14 |         self.0.try_field_ref()
   |                ^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound for `R`
note: the parameter type `R` must be valid for the anonymous lifetime #1 defined on the method body at 13:5...
  --> src/lib.rs:13:5
   |
13 | /     fn try_field_ref<F:Field>(&self)->Option<&F> {
14 | |         self.0.try_field_ref()
15 | |     }
   | |_____^
note: ...so that the reference type `&R` does not outlive the data it points at
  --> src/lib.rs:14:16
   |
14 |         self.0.try_field_ref()
   |                ^^^^^^^^^^^^^

error: aborting due to 2 previous errors

error: could not compile `playground`.

To learn more, run the command again with --verbose.

Huh, this is an interesting case. It seems like the compiler can't tell that the type R must be valid whenever Lazy<Ptr> is.

1 Like
Intermediate diagnostic information

In trying to make it as explicit as possible, things start to look a bit stranger:

impl<Ptr:Deref<Target=R>, R:Record> Record for Lazy<Ptr> {
    fn try_field_ref<'a, F:Field>(&'a self)->Option<&'a F> {
        let ptr: &'a Ptr = &self.0;
        let inner: &'a <Ptr as Deref>::Target = <Ptr as Deref>::deref(ptr);
        <<Ptr as Deref>::Target as Record>::try_field_ref(inner)
    }
}

Manifests the same error, substituting R for the explicit type reference I used:

error[E0309]: the parameter type `R` may not live long enough
  --> src/lib.rs:15:20
   |
12 | impl<Ptr:Deref<Target=R>, R:Record> Record for Lazy<Ptr> {
   |                           -- help: consider adding an explicit lifetime bound...: `R: 'a +`
...
15 |         let inner: &'a <Ptr as Deref>::Target = <Ptr as Deref>::deref(ptr);
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: ...so that the reference type `&'a R` does not outlive the data it points at
  --> src/lib.rs:15:20
   |
15 |         let inner: &'a <Ptr as Deref>::Target = <Ptr as Deref>::deref(ptr);
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^

Apparently, removing the type parameter allows it to compile; this works:

impl<Ptr:Deref> Record for Lazy<Ptr> where Ptr::Target: Record {
    fn try_field_ref<'a, F:Field>(&'a self)->Option<&'a F> {
        let ptr: &'a Ptr = &self.0;
        let inner: &'a <Ptr as Deref>::Target = <Ptr as Deref>::deref(ptr);
        <<Ptr as Deref>::Target as Record>::try_field_ref(inner)
    }
}
1 Like
1 Like