|
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