Skip to content

Commit de3e95b

Browse files
Review updates: simpler MWE and docs
- use the simpler minimum working example from the review - add an alterate "fix" that helps make the cause of the error more clear - attempt to add an improved description of what is going on
1 parent 4f194a7 commit de3e95b

File tree

3 files changed

+52
-100
lines changed

3 files changed

+52
-100
lines changed
Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,52 @@
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.
33

44
Erroneous code example:
55

66
```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)
119
}
1210
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
2313
}
2414
```
2515

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]
3120

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.
3725

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`.
4529

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+
}
4934
50-
Here is the working version of the code:
35+
fn with_restriction<'a>(x: &'a ()) -> &'a () {
36+
x
37+
}
5138
```
52-
use std::borrow::BorrowMut;
5339

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)
5647
}
5748
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
6851
}
6952
```

src/test/ui/error-codes/E0311.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
1-
use std::borrow::BorrowMut;
2-
3-
trait NestedBorrowMut<U, V> {
4-
fn nested_borrow_mut(&mut self) -> &mut V;
1+
fn no_restriction<T>(x: &()) -> &() {
2+
with_restriction::<T>(x) //~ ERROR E0311
53
}
64

7-
impl<T, U, V> NestedBorrowMut<U, V> for T
8-
where
9-
T: BorrowMut<U>,
10-
U: BorrowMut<V>, // Error is caused by missing lifetime here
11-
{
12-
fn nested_borrow_mut(&mut self) -> &mut V {
13-
let u_ref = self.borrow_mut(); //~ ERROR E0311
14-
let v_ref = u_ref.borrow_mut(); //~ ERROR E0311
15-
v_ref
16-
}
5+
fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
6+
x
177
}
188

199
fn main() {}

src/test/ui/error-codes/E0311.stderr

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,24 @@
1-
error[E0311]: the parameter type `U` may not live long enough
2-
--> $DIR/E0311.rs:13:21
1+
error[E0311]: the parameter type `T` may not live long enough
2+
--> $DIR/E0311.rs:2:5
33
|
4-
LL | let u_ref = self.borrow_mut();
5-
| ^^^^^^^^^^^^^^^^^
4+
LL | with_restriction::<T>(x)
5+
| ^^^^^^^^^^^^^^^^^^^^^
66
|
7-
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
8-
--> $DIR/E0311.rs:12:26
7+
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
8+
--> $DIR/E0311.rs:1:25
99
|
10-
LL | fn nested_borrow_mut(&mut self) -> &mut V {
11-
| ^^^^^^^^^
12-
note: ...so that the type `U` will meet its required lifetime bounds
13-
--> $DIR/E0311.rs:13:21
10+
LL | fn no_restriction<T>(x: &()) -> &() {
11+
| ^^^
12+
note: ...so that the type `T` will meet its required lifetime bounds
13+
--> $DIR/E0311.rs:2:5
1414
|
15-
LL | let u_ref = self.borrow_mut();
16-
| ^^^^^^^^^^^^^^^^^
15+
LL | with_restriction::<T>(x)
16+
| ^^^^^^^^^^^^^^^^^^^^^
1717
help: consider adding an explicit lifetime bound...
1818
|
19-
LL | U: BorrowMut<V> + 'a, // Error is caused by missing lifetime here
20-
| ++++
19+
LL | fn no_restriction<T: 'a>(x: &()) -> &() {
20+
| ++++
2121

22-
error[E0311]: the parameter type `U` may not live long enough
23-
--> $DIR/E0311.rs:14:21
24-
|
25-
LL | let v_ref = u_ref.borrow_mut();
26-
| ^^^^^^^^^^^^^^^^^^
27-
|
28-
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
29-
--> $DIR/E0311.rs:12:26
30-
|
31-
LL | fn nested_borrow_mut(&mut self) -> &mut V {
32-
| ^^^^^^^^^
33-
note: ...so that the type `U` will meet its required lifetime bounds
34-
--> $DIR/E0311.rs:14:21
35-
|
36-
LL | let v_ref = u_ref.borrow_mut();
37-
| ^^^^^^^^^^^^^^^^^^
38-
help: consider adding an explicit lifetime bound...
39-
|
40-
LL | U: BorrowMut<V> + 'a, // Error is caused by missing lifetime here
41-
| ++++
42-
43-
error: aborting due to 2 previous errors
22+
error: aborting due to previous error
4423

4524
For more information about this error, try `rustc --explain E0311`.

0 commit comments

Comments
 (0)