IntoIterator/Iterate by ref (non-consuming) trait bound

This is mostly explained in the collapsed "longer explanation". The lifetime is transferred by an implied bound: if the signature of a generic fn, type, trait, or impl directly includes a type &'a T, it automatically receives the implicit bound T: 'a. If this bound were not met, the type or trait wouldn't make any sense; it would be ill-formed. First, to illustrate well-formedness, a &'static &'a str cannot even be referred to:

pub fn example<'a>() {
    let _o: Option<&'static &'a str> = None;
}
error[E0491]: in type `&'static &'a str`, reference has a longer lifetime than the data it references
 --> src/lib.rs:2:13
  |
2 |     let _o: Option<&'static &'a str> = None;
  |             ^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: the pointer is valid for the static lifetime
note: but the referenced data is only valid for the lifetime `'a` as defined here
 --> src/lib.rs:1:16
  |
1 | pub fn example<'a>() {
  |                ^^

For more information about this error, try `rustc --explain E0491`.
error: could not compile `wat` due to previous error

For the type system to be sound, it is important never to create ill-formed types through any means. The explanation for E0491 gives an example which illustrates this:

struct Foo<'a> {
    x: fn(&'a i32),
}

trait Trait<'a, 'b> {
    type Out;
}

impl<'a, 'b> Trait<'a, 'b> for usize {
    type Out = &'a Foo<'b>; // error!
}

If this were allowed, we could get around the well-formedness restrictions by writing <usize as Trait<'static, 'a>>::Out instead of &'static Foo<'a>. Instead, we must repeat the required bound on the impl, so that usize can no longer implement Trait<'static, 'a> (unless 'a: 'static):

-impl<'a, 'b> Trait<'a, 'b> for usize {
+impl<'a, 'b: 'a> Trait<'a, 'b> for usize {
     type Out = &'a Foo<'b>;
 }

However, writing these bounds explicitly everywhere would quickly become tedious. So when a type with well-formedness restrictions such as &'a Foo<'b> is referenced directly by a declaration, the compiler adds the implied bound 'b: 'a to prevent ill-formed usage.


In this particular scenario, the _LifetimeHack = &'a Self adds an implicit Self: 'a bound to NonconsumingIter<'a>. So when we write T: for<'any> NonconsumingIter<'any>, the compiler understands this to mean "T: NonconsumingIter<'any> for all lifetimes 'any such that NonconsumingIter<'any> is well-formed, i.e., all lifetimes 'any such that T: 'any". Without the implied bound, it would instead mean "T: NonconsumingIter<'any> for all lifetimes 'any, up to and including 'static", which can only hold when T: 'static.

1 Like