1- This error occurs when there is insufficient information for the rust compiler
2- to prove that a type has a long enough lifetime .
1+ This error occurs when there is an unsatisfied outlives bound on a generic
2+ type parameter or associated type .
33
44Erroneous code example:
55
@@ -13,58 +13,63 @@ trait NestedBorrowMut<U, V> {
1313impl<T, U, V> NestedBorrowMut<U, V> for T
1414where
1515 T: BorrowMut<U>,
16- U: BorrowMut<V>, // error: missing lifetime specifier
16+ U: BorrowMut<V>,
1717{
1818 fn nested_borrow_mut(&mut self) -> &mut V {
19- self.borrow_mut().borrow_mut()
19+ let u_ref = self.borrow_mut();
20+ let v_ref = u_ref.borrow_mut();
21+ v_ref
2022 }
2123}
2224```
2325
24- Why doesn't this code compile? The problem has to do with Rust's rules for
25- lifetime elision in functions (Chapter 10.3 in the Rust book). One of the
26- inputs is a reference to ` self ` , so the compiler attempts to assign the
27- the same lifetime to the ` &mut self ` input and ` &mut V ` output to the
28- ` nested_borrow_mut() ` function. The problem is that there is no way for the
29- compiler to directly figure out how these two lifetimes are related in the
30- implementation of the function. We're implementing the ` NextedBorrowMut `
31- trait for a type ` T ` , so the ` &mut self ` reference has the lifetime of ` T ` .
32- We know that ` T ` implements the ` BorrowMut ` trait returning a reference to ` U ` ,
33- and that ` U ` implements the ` BorrowMut ` trait returning a reference to ` V ` .
34- The key is that we have not told the compiler that those two ` U ` lifetimes
35- are the same: for all it knows, we could be that the first ` BorrowMut ` trait
36- on ` T ` works with a lifetime ` 'a ` and the second ` BorrowMut ` trait on ` U `
37- works on a lifetime ` 'b ` .
26+ Why doesn't this code compile? It helps to look at the lifetime bounds that
27+ the compiler is automatically adding ("Lifetime Ellision", Chapter 10.3 in the
28+ Rust book) to the ` nested_borrow_mut ` and ` borrow_mut ` functions. In both cases
29+ the input is a reference to ` self ` , so the compiler attempts to assign the
30+ the same lifetime to the input and output.
3831
39- The fix here is to add explicit lifetime annotations that tell the compiler
40- that the lifetime of the output is in fact the same as the lifetime of the
41- input (` self ` ). There are three references involved, to objects of type ` T `
42- (` self ` ), ` U ` (the intermediate type), and ` V ` (the return type). In the
43- working code below, we see that all have been given the same lifetime ` 'a ` :
44- - ` &'a mut self ` in the function argument list for ` T `
45- - ` U: BorrowMut<V> + 'a ` in the trait bounds for ` U `
46- - ` &'a mut V ` in the function return for ` V ` .
32+ Looking specifically at ` nested_borrow_mut ` ,
33+ we see that there are three object references to keep track of,
34+ along with their associated lifetimes:
35+ - ` self ` (which is a ` &mut T ` )
36+ - ` u_ref ` (which is a ` &mut U ` )
37+ - ` v_ref ` (which is a ` &mut V ` )
4738
48- The compiler can the check that the implementation of the
49- ` nested_borrow_mut() ` function satisfies these lifetimes. There are two
50- functions being called inside of ` nested_borrow_mut() ` , both of which are
51- the ` borrow_mut() ` function, which promises that the output lifetime is
52- the same as the input lifetime (see lifetime elision rules), which checks out.
39+ The ` borrow_mut() ` method implicitly requires that that the input and output
40+ have the same lifetime bounds. Thus:
5341
42+ ``` rust
43+ let u_ref = self . borrow_mut ();
44+ let v_ref = u_ref . borrow_mut ();
5445```
46+
47+ Imply that ` u_ref ` and ` self ` must share a lifetime bound, and also that
48+ ` v_ref ` and ` u_ref ` share a lifetime bound. The problem is that the function
49+ signature for ` nested_borrow_mut ` only gives the compiler information about the
50+ lifetimes of ` self ` and ` v_ref ` -- nothing about ` u_ref ` .
51+
52+ The way to fix this error is then to explicitly tell the compiler that the
53+ lifetime of ` u_ref ` is the same as ` self ` and ` v_ref ` , which then allows it
54+ to satisfy the two lifetime bound requirements described above.
55+
56+ Here is the working version of the code:
57+ ``` rust
5558use std :: borrow :: BorrowMut ;
5659
5760trait NestedBorrowMut <'a , U , V > {
58- fn nested_borrow_mut(& 'a mut self) -> &'a mut V;
61+ fn nested_borrow_mut (& 'a mut self ) -> & 'a mut V ;
5962}
6063
6164impl <'a , T , U , V > NestedBorrowMut <'a , U , V > for T
6265where
6366 T : BorrowMut <U >,
64- U: BorrowMut<V> + 'a, // Adding lifetime specifier
67+ U : BorrowMut <V > + 'a ,
6568{
6669 fn nested_borrow_mut (& 'a mut self ) -> & 'a mut V {
67- self.borrow_mut().borrow_mut()
70+ let u_ref = self . borrow_mut ();
71+ let v_ref = u_ref . borrow_mut ();
72+ v_ref
6873 }
6974}
7075```
0 commit comments