|
1 |
| -This error occurs when there is an unsatisfied outlives bound on a generic |
2 |
| -type parameter or associated type. |
| 1 | +This error occurs when there is an unsatisfied outlives bound involving an |
| 2 | +elided region on a generic type parameter or associated type. |
3 | 3 |
|
4 | 4 | Erroneous code example:
|
5 | 5 |
|
6 | 6 | ```compile_fail,E0311
|
7 |
| -use std::borrow::BorrowMut; |
8 |
| -
|
9 |
| -trait NestedBorrowMut<U, V> { |
10 |
| - fn nested_borrow_mut(&mut self) -> &mut V; |
| 7 | +fn no_restriction<T>(x: &()) -> &() { |
| 8 | + with_restriction::<T>(x) |
11 | 9 | }
|
12 | 10 |
|
13 |
| -impl<T, U, V> NestedBorrowMut<U, V> for T |
14 |
| -where |
15 |
| - T: BorrowMut<U>, |
16 |
| - U: BorrowMut<V>, |
17 |
| -{ |
18 |
| - fn nested_borrow_mut(&mut self) -> &mut V { |
19 |
| - let u_ref = self.borrow_mut(); |
20 |
| - let v_ref = u_ref.borrow_mut(); |
21 |
| - v_ref |
22 |
| - } |
| 11 | +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { |
| 12 | + x |
23 | 13 | }
|
24 | 14 | ```
|
25 | 15 |
|
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 |
29 |
| -cases the input is a reference to `self`, so the compiler attempts to assign |
30 |
| -the same lifetime to the input and output. |
| 16 | +Why doesn't this code compile? It helps to look at the lifetime bounds that are |
| 17 | +automatically adding by the compiler. For more details see the Rust |
| 18 | +Documentation for Lifetime Elision: |
| 19 | +https://doc.rust-lang.org/reference/lifetime-elision.html] |
31 | 20 |
|
32 |
| -Looking specifically at `nested_borrow_mut()`, we see that there are three |
33 |
| -object references to keep track of, along with their associated lifetimes: |
34 |
| -- `self` (which is a `&mut T`) |
35 |
| -- `u_ref` (which is a `&mut U`) |
36 |
| -- `v_ref` (which is a `&mut V`) |
| 21 | +There are two lifetimes being passed into the `no_restriction()` function: one |
| 22 | +associated with the generic type `T` parameter and the other with the input |
| 23 | +argument `x`. The compiler does not know which of these lifetimes can be |
| 24 | +assigned to the output reference, so we get an error. |
37 | 25 |
|
38 |
| -The `borrow_mut()` method implicitly requires that that the input and output |
39 |
| -have the same lifetime bounds. Thus the lines: `let u_ref = self.borrow_mut();` |
40 |
| -and `let v_ref = u_ref.borrow_mut();` in `nested_borrow_mut()` above imply that |
41 |
| -`u_ref` and `self` must share a lifetime bound, and also that `v_ref` and |
42 |
| -`u_ref` share a lifetime bound. The problem is that the function signature for |
43 |
| -`nested_borrow_mut()` only gives the compiler information about the lifetimes |
44 |
| -of `self` and `v_ref` -- nothing about `u_ref`. |
| 26 | +One way to "fix" this code would be to remove the generic type argument `T`. |
| 27 | +In this case, the lifetime elision works because there is a single input |
| 28 | +lifetime, which is associated with `x`. |
45 | 29 |
|
46 |
| -The way to fix this error is then to explicitly tell the compiler that the |
47 |
| -lifetime of `u_ref` is the same as `self` and `v_ref`, which then allows it |
48 |
| -to satisfy the two lifetime bound requirements described above. |
| 30 | +``` |
| 31 | +fn no_restriction(x: &()) -> &() { |
| 32 | + with_restriction(x) |
| 33 | +} |
49 | 34 |
|
50 |
| -Here is the working version of the code: |
| 35 | +fn with_restriction<'a>(x: &'a ()) -> &'a () { |
| 36 | + x |
| 37 | +} |
51 | 38 | ```
|
52 |
| -use std::borrow::BorrowMut; |
53 | 39 |
|
54 |
| -trait NestedBorrowMut<'a, U, V> { |
55 |
| - fn nested_borrow_mut(&'a mut self) -> &'a mut V; |
| 40 | +The "correct" way to resolve this error is to explicitly tell the compiler |
| 41 | +which input lifetime should be assigned to the output. In this case we give |
| 42 | +both the generic type `T` parameter and the argument `x` the same lifetime |
| 43 | +requirement as the output reference, producing a working version of the code: |
| 44 | +``` |
| 45 | +fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { |
| 46 | + with_restriction::<T>(x) |
56 | 47 | }
|
57 | 48 |
|
58 |
| -impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T |
59 |
| -where |
60 |
| - T: BorrowMut<U>, |
61 |
| - U: BorrowMut<V> + 'a, |
62 |
| -{ |
63 |
| - fn nested_borrow_mut(&'a mut self) -> &'a mut V { |
64 |
| - let u_ref = self.borrow_mut(); |
65 |
| - let v_ref = u_ref.borrow_mut(); |
66 |
| - v_ref |
67 |
| - } |
| 49 | +fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () { |
| 50 | + x |
68 | 51 | }
|
69 | 52 | ```
|
0 commit comments