about summary refs log tree commit diff
path: root/compiler/rustc_error_codes
diff options
context:
space:
mode:
authorMatthew Kelly <matthew.kelly2@gmail.com>2022-08-26 15:01:49 -0400
committerMatthew Kelly <matthew.kelly2@gmail.com>2022-08-27 14:20:59 -0400
commitde3e95b56c3c1af339a6c13dc8875599e553aa98 (patch)
tree2e3adad0e8c1dfa3afc72a748627ef274d12b65a /compiler/rustc_error_codes
parent4f194a76c8482ffcd16526a08b1dc489a5a75e96 (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
Diffstat (limited to 'compiler/rustc_error_codes')
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0311.md83
1 files changed, 33 insertions, 50 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
 }
 ```