-This error occurs when there is insufficient information for the rust compiler
-to prove that a type has a long enough lifetime.
+This error occurs when there is an unsatisfied outlives bound on a generic
+type parameter or associated type.
Erroneous code example:
impl<T, U, V> NestedBorrowMut<U, V> for T
where
T: BorrowMut<U>,
- U: BorrowMut<V>, // error: missing lifetime specifier
+ U: BorrowMut<V>,
{
fn nested_borrow_mut(&mut self) -> &mut V {
- self.borrow_mut().borrow_mut()
+ let u_ref = self.borrow_mut();
+ let v_ref = u_ref.borrow_mut();
+ v_ref
}
}
```
-Why doesn't this code compile? The problem has to do with Rust's rules for
-lifetime elision in functions (Chapter 10.3 in the Rust book). One of the
-inputs is a reference to `self`, so the compiler attempts to assign the
-the same lifetime to the `&mut self` input and `&mut V` output to the
-`nested_borrow_mut()` function. The problem is that there is no way for the
-compiler to directly figure out how these two lifetimes are related in the
-implementation of the function. We're implementing the `NextedBorrowMut`
-trait for a type `T`, so the `&mut self` reference has the lifetime of `T`.
-We know that `T` implements the `BorrowMut` trait returning a reference to `U`,
-and that `U` implements the `BorrowMut` trait returning a reference to `V`.
-The key is that we have not told the compiler that those two `U` lifetimes
-are the same: for all it knows, we could be that the first `BorrowMut` trait
-on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U`
-works on a lifetime `'b`.
+Why doesn't this code compile? It helps to look at the lifetime bounds that
+the compiler is automatically adding ("Lifetime Ellision", Chapter 10.3 in the
+Rust book) to the `nested_borrow_mut` and `borrow_mut` functions. In both cases
+the input is a reference to `self`, so the compiler attempts to assign the
+the same lifetime to the input and output.
-The fix here is to add explicit lifetime annotations that tell the compiler
-that the lifetime of the output is in fact the same as the lifetime of the
-input (`self`). There are three references involved, to objects of type `T`
-(`self`), `U` (the intermediate type), and `V` (the return type). In the
-working code below, we see that all have been given the same lifetime `'a`:
-- `&'a mut self` in the function argument list for `T`
-- `U: BorrowMut<V> + 'a` in the trait bounds for `U`
-- `&'a mut V` in the function return for `V`.
+Looking specifically at `nested_borrow_mut`,
+we see that there are three object references to keep track of,
+along with their associated lifetimes:
+- `self` (which is a `&mut T`)
+- `u_ref` (which is a `&mut U`)
+- `v_ref` (which is a `&mut V`)
-The compiler can the check that the implementation of the
-`nested_borrow_mut()` function satisfies these lifetimes. There are two
-functions being called inside of `nested_borrow_mut()`, both of which are
-the `borrow_mut()` function, which promises that the output lifetime is
-the same as the input lifetime (see lifetime elision rules), which checks out.
+The `borrow_mut()` method implicitly requires that that the input and output
+have the same lifetime bounds. Thus:
+```rust
+ let u_ref = self.borrow_mut();
+ let v_ref = u_ref.borrow_mut();
```
+
+Imply that `u_ref` and `self` must share a lifetime bound, and also that
+`v_ref` and `u_ref` share a lifetime bound. The problem is that the function
+signature for `nested_borrow_mut` only gives the compiler information about the
+lifetimes of `self` and `v_ref` -- nothing about `u_ref`.
+
+The way to fix this error is then to explicitly tell the compiler that the
+lifetime of `u_ref` is the same as `self` and `v_ref`, which then allows it
+to satisfy the two lifetime bound requirements described above.
+
+Here is the working version of the code:
+```rust
use std::borrow::BorrowMut;
trait NestedBorrowMut<'a, U, V> {
- fn nested_borrow_mut(& 'a mut self) -> &'a mut V;
+ fn nested_borrow_mut(&'a mut self) -> &'a mut V;
}
impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T
where
T: BorrowMut<U>,
- U: BorrowMut<V> + 'a, // Adding lifetime specifier
+ U: BorrowMut<V> + 'a,
{
fn nested_borrow_mut(&'a mut self) -> &'a mut V {
- self.borrow_mut().borrow_mut()
+ let u_ref = self.borrow_mut();
+ let v_ref = u_ref.borrow_mut();
+ v_ref
}
}
```