Search code examples
rustlanguage-lawyerlifetime

Does &'a T imply T: 'a?


From my own understanding and experimentation this appears to be true, but I have yet to find an authoritative source that documents it. Rust by Example has a bounds section where it says:

T: 'a: All references in T must outlive lifetime 'a.

#[derive(Debug)]
struct Ref<'a, T: 'a>(&'a T);
// `Ref` contains a reference to a generic type `T` that has
// an unknown lifetime `'a`. `T` is bounded such that any
// *references* in `T` must outlive `'a`. Additionally, the lifetime
// of `Ref` may not exceed `'a`.

However, this looks like a poor demonstration since the T: 'a bound does not seem to affect the behavior of Ref. Any attempt I've made to construct a T that is shorter than 'a is thwarted with or without T: 'a. Even more, a generic reference defined without the lifetime bound can be passed off as one with it:

fn f<'a, T>(r: &'a T) {
    g(r) // this compiles
}

fn g<'a, T: 'a>(r: &'a T) {
    // ...
}

The Rust Reference has a similar construction from some examples in the generic parameters section (struct Ref<'a, T> where T: 'a { r: &'a T }), however it does not elaborate. I have looked through the documentation there, those on references, and on lifetimes and cannot find a link.

So does &'a T imply T: 'a? If so, where is this documented? And why do these resources have this unnecessary constraint? If not, what are the rules?


Solution

  • Yes, &'a T does imply T: 'a.

    There was always the requirement that referent had to outlive the referenced lifetime since it is necessary for safety by-construction. However, before Rust 1.31 the bound was not inferred and would have to be provided explicitly as shown in these questions.

    It was RFC #2093: infer outlives that let the compiler to infer these bounds and thus allowed the user to elide them. Since then, the Rust by Example and Rust Reference snippets are over-specified and the T: 'a is no longer needed.

    See elsewhere in the Reference on trait and lifetime bounds:

    Lifetime bounds required for types to be well-formed are sometimes inferred.

    fn requires_t_outlives_a<'a, T>(x: &'a T) {}
    

    The type parameter T is required to outlive 'a for the type &'a T to be well-formed. This is inferred because the function signature contains the type &'a T which is only valid if T: 'a holds.


    There is at least one place where &'a T does not automatically infer T: 'a and that is when defining associated types for a trait (demo on the playground) but the compiler will guide you into adding it explicitly:

    trait MakeRef<'a> {
        type Type;
    }
    
    impl<'a, T> MakeRef<'a> for Vec<T> {
        type Type = &'a T;
    }
    
    error[E0309]: the parameter type `T` may not live long enough
     --> src/lib.rs:6:17
      |
    6 |     type Type = &'a T;
      |                 ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
      |
    help: consider adding an explicit lifetime bound...
      |
    5 | impl<'a, T: 'a> MakeRef<'a> for Vec<T> {
      |           ++++