]> git.lizzy.rs Git - rust.git/commitdiff
Review updates: simpler MWE and docs
authorMatthew Kelly <matthew.kelly2@gmail.com>
Fri, 26 Aug 2022 19:01:49 +0000 (15:01 -0400)
committerMatthew Kelly <matthew.kelly2@gmail.com>
Sat, 27 Aug 2022 18:20:59 +0000 (14:20 -0400)
- 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

compiler/rustc_error_codes/src/error_codes/E0311.md
src/test/ui/error-codes/E0311.rs
src/test/ui/error-codes/E0311.stderr

index f8c04d54db70a59500d6f103e9f4e446ff001c60..b1fa61d365c73c781387ab3a9aeea5baa2c9cd3b 100644 (file)
@@ -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
 }
 ```
index 95f8602306cdec69705b427540660f33ac444e1b..566b518b4331dec8dec96379f1a10649698193eb 100644 (file)
@@ -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() {}
index 2cf6404f2f1c0265eb3dec8d20240884d417c219..bc0182555af864b90268810542e1a1b264117216 100644 (file)
@@ -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`.