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
This commit is contained in:
parent
4f194a76c8
commit
de3e95b56c
@ -1,69 +1,52 @@
|
||||
This error occurs when there is an unsatisfied outlives bound on a generic
|
||||
type parameter or associated type.
|
||||
This error occurs when there is an unsatisfied outlives bound involving an
|
||||
elided region on a generic type parameter or associated type.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0311
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
trait NestedBorrowMut<U, V> {
|
||||
fn nested_borrow_mut(&mut self) -> &mut V;
|
||||
fn no_restriction<T>(x: &()) -> &() {
|
||||
with_restriction::<T>(x)
|
||||
}
|
||||
|
||||
impl<T, U, V> NestedBorrowMut<U, V> for T
|
||||
where
|
||||
T: BorrowMut<U>,
|
||||
U: BorrowMut<V>,
|
||||
{
|
||||
fn nested_borrow_mut(&mut self) -> &mut V {
|
||||
let u_ref = self.borrow_mut();
|
||||
let v_ref = u_ref.borrow_mut();
|
||||
v_ref
|
||||
}
|
||||
fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
|
||||
x
|
||||
}
|
||||
```
|
||||
|
||||
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 same lifetime to the input and output.
|
||||
Why doesn't this code compile? It helps to look at the lifetime bounds that are
|
||||
automatically adding by the compiler. For more details see the Rust
|
||||
Documentation for Lifetime Elision:
|
||||
https://doc.rust-lang.org/reference/lifetime-elision.html]
|
||||
|
||||
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`)
|
||||
There are two lifetimes being passed into the `no_restriction()` function: one
|
||||
associated with the generic type `T` parameter and the other with the input
|
||||
argument `x`. The compiler does not know which of these lifetimes can be
|
||||
assigned to the output reference, so we get an error.
|
||||
|
||||
The `borrow_mut()` method implicitly requires that that the input and output
|
||||
have the same lifetime bounds. Thus the lines: `let u_ref = self.borrow_mut();`
|
||||
and `let v_ref = u_ref.borrow_mut();` in `nested_borrow_mut()` above 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`.
|
||||
One way to "fix" this code would be to remove the generic type argument `T`.
|
||||
In this case, the lifetime elision works because there is a single input
|
||||
lifetime, which is associated with `x`.
|
||||
|
||||
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:
|
||||
```
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
trait NestedBorrowMut<'a, U, V> {
|
||||
fn nested_borrow_mut(&'a mut self) -> &'a mut V;
|
||||
fn no_restriction(x: &()) -> &() {
|
||||
with_restriction(x)
|
||||
}
|
||||
|
||||
impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T
|
||||
where
|
||||
T: BorrowMut<U>,
|
||||
U: BorrowMut<V> + 'a,
|
||||
{
|
||||
fn nested_borrow_mut(&'a mut self) -> &'a mut V {
|
||||
let u_ref = self.borrow_mut();
|
||||
let v_ref = u_ref.borrow_mut();
|
||||
v_ref
|
||||
}
|
||||
fn with_restriction<'a>(x: &'a ()) -> &'a () {
|
||||
x
|
||||
}
|
||||
```
|
||||
|
||||
The "correct" way to resolve this error is to explicitly tell the compiler
|
||||
which input lifetime should be assigned to the output. In this case we give
|
||||
both the generic type `T` parameter and the argument `x` the same lifetime
|
||||
requirement as the output reference, producing a working version of the code:
|
||||
```
|
||||
fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
|
||||
with_restriction::<T>(x)
|
||||
}
|
||||
|
||||
fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
|
||||
x
|
||||
}
|
||||
```
|
||||
|
@ -1,19 +1,9 @@
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
trait NestedBorrowMut<U, V> {
|
||||
fn nested_borrow_mut(&mut self) -> &mut V;
|
||||
fn no_restriction<T>(x: &()) -> &() {
|
||||
with_restriction::<T>(x) //~ ERROR E0311
|
||||
}
|
||||
|
||||
impl<T, U, V> NestedBorrowMut<U, V> for T
|
||||
where
|
||||
T: BorrowMut<U>,
|
||||
U: BorrowMut<V>, // Error is caused by missing lifetime here
|
||||
{
|
||||
fn nested_borrow_mut(&mut self) -> &mut V {
|
||||
let u_ref = self.borrow_mut(); //~ ERROR E0311
|
||||
let v_ref = u_ref.borrow_mut(); //~ ERROR E0311
|
||||
v_ref
|
||||
}
|
||||
fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,45 +1,24 @@
|
||||
error[E0311]: the parameter type `U` may not live long enough
|
||||
--> $DIR/E0311.rs:13:21
|
||||
error[E0311]: the parameter type `T` may not live long enough
|
||||
--> $DIR/E0311.rs:2:5
|
||||
|
|
||||
LL | let u_ref = self.borrow_mut();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | with_restriction::<T>(x)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
|
||||
--> $DIR/E0311.rs:12:26
|
||||
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
|
||||
--> $DIR/E0311.rs:1:25
|
||||
|
|
||||
LL | fn nested_borrow_mut(&mut self) -> &mut V {
|
||||
| ^^^^^^^^^
|
||||
note: ...so that the type `U` will meet its required lifetime bounds
|
||||
--> $DIR/E0311.rs:13:21
|
||||
LL | fn no_restriction<T>(x: &()) -> &() {
|
||||
| ^^^
|
||||
note: ...so that the type `T` will meet its required lifetime bounds
|
||||
--> $DIR/E0311.rs:2:5
|
||||
|
|
||||
LL | let u_ref = self.borrow_mut();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | with_restriction::<T>(x)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | U: BorrowMut<V> + 'a, // Error is caused by missing lifetime here
|
||||
| ++++
|
||||
LL | fn no_restriction<T: 'a>(x: &()) -> &() {
|
||||
| ++++
|
||||
|
||||
error[E0311]: the parameter type `U` may not live long enough
|
||||
--> $DIR/E0311.rs:14:21
|
||||
|
|
||||
LL | let v_ref = u_ref.borrow_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
|
||||
--> $DIR/E0311.rs:12:26
|
||||
|
|
||||
LL | fn nested_borrow_mut(&mut self) -> &mut V {
|
||||
| ^^^^^^^^^
|
||||
note: ...so that the type `U` will meet its required lifetime bounds
|
||||
--> $DIR/E0311.rs:14:21
|
||||
|
|
||||
LL | let v_ref = u_ref.borrow_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: consider adding an explicit lifetime bound...
|
||||
|
|
||||
LL | U: BorrowMut<V> + 'a, // Error is caused by missing lifetime here
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0311`.
|
||||
|
Loading…
Reference in New Issue
Block a user