]> git.lizzy.rs Git - rust.git/commitdiff
Improve E0311.md description
authorMatthew Kelly <matthew.kelly2@gmail.com>
Tue, 23 Aug 2022 09:19:04 +0000 (05:19 -0400)
committerMatthew Kelly <matthew.kelly2@gmail.com>
Tue, 23 Aug 2022 09:19:04 +0000 (05:19 -0400)
compiler/rustc_error_codes/src/error_codes/E0311.md

index 9477a0b1fb76a7b2128072d98f8d8f4d856f3952..00b23c420529febd14c0045e0708a928a776d3d4 100644 (file)
@@ -21,14 +21,35 @@ where
 }
 ```
 
-In this example we have a trait that borrows some inner data element of type `V`
-from an outer type `T`, through an intermediate type `U`. The compiler is unable
-to prove that the livetime of `U` is long enough to support the reference. To
-fix the issue we can explicitly add lifetime specifiers to the `NestedBorrowMut`
-trait, which link the lifetimes of the various data types and allow the code to
-compile.
-
-Working implementation of the `NestedBorrowMut` trait:
+Why doesn't this code compile? The problem has to do with Rust's rules for
+lifetime elision in functions (Chapter 10.3 in the Rust book). One of the
+inputs is a reference to `self`, so the compiler attempts to assign the
+the same lifetime to the `&mut self` input and `&mut V` output to the
+`nested_borrow_mut()` function. The problem is that there is no way for the
+compiler to directly figure out how these two lifetimes are related in the
+implementation of the function. We're implementing the `NextedBorrowMut`
+trait for a type `T`, so the `&mut self` reference has the lifetime of `T`.
+We know that `T` implements the `BorrowMut` trait returning a reference to `U`,
+and that `U` implements the `BorrowMut` trait returning a reference to `V`.
+The key is that we have not told the compiler that those two `U` lifetimes
+are the same: for all it knows, we could be that the first `BorrowMut` trait
+on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U`
+works on a lifetime `'b`.
+
+The fix here is to add explicit lifetime annotations that tell the compiler
+that the lifetime of the output is in fact the same as the lifetime of the
+input (`self`). There are three references involved, to objects of type `T`
+(`self`), `U` (the intermediate type), and `V` (the return type). In the
+working code below, we see that all have been given the same lifetime `'a`:
+- `&'a mut self` in the function argument list for `T`
+- `U: BorrowMut<V> + 'a` in the trait bounds for `U`
+- `&'a mut V` in the function return for `V`.
+
+The compiler can the check that the implementation of the
+`nested_borrow_mut()` function satisfies these lifetimes. There are two
+functions being called inside of `nested_borrow_mut()`, both of which are
+the `borrow_mut()` function, which promises that the output lifetime is
+the same as the input lifetime (see lifetime elision rules), which checks out.
 
 ```
 use std::borrow::BorrowMut;