diff options
| author | Matthew Kelly <matthew.kelly2@gmail.com> | 2022-08-26 15:01:49 -0400 |
|---|---|---|
| committer | Matthew Kelly <matthew.kelly2@gmail.com> | 2022-08-27 14:20:59 -0400 |
| commit | de3e95b56c3c1af339a6c13dc8875599e553aa98 (patch) | |
| tree | 2e3adad0e8c1dfa3afc72a748627ef274d12b65a | |
| parent | 4f194a76c8482ffcd16526a08b1dc489a5a75e96 (diff) | |
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
| -rw-r--r-- | compiler/rustc_error_codes/src/error_codes/E0311.md | 83 | ||||
| -rw-r--r-- | src/test/ui/error-codes/E0311.rs | 18 | ||||
| -rw-r--r-- | src/test/ui/error-codes/E0311.stderr | 51 |
3 files changed, 52 insertions, 100 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md index f8c04d54db7..b1fa61d365c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0311.md +++ b/compiler/rustc_error_codes/src/error_codes/E0311.md @@ -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. +``` +fn no_restriction(x: &()) -> &() { + with_restriction(x) +} -Here is the working version of the code: +fn with_restriction<'a>(x: &'a ()) -> &'a () { + x +} ``` -use std::borrow::BorrowMut; -trait NestedBorrowMut<'a, U, V> { - fn nested_borrow_mut(&'a mut self) -> &'a mut V; +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) } -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, T: 'a>(x: &'a ()) -> &'a () { + x } ``` diff --git a/src/test/ui/error-codes/E0311.rs b/src/test/ui/error-codes/E0311.rs index 95f8602306c..566b518b433 100644 --- a/src/test/ui/error-codes/E0311.rs +++ b/src/test/ui/error-codes/E0311.rs @@ -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() {} diff --git a/src/test/ui/error-codes/E0311.stderr b/src/test/ui/error-codes/E0311.stderr index 2cf6404f2f1..bc0182555af 100644 --- a/src/test/ui/error-codes/E0311.stderr +++ b/src/test/ui/error-codes/E0311.stderr @@ -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`. |
