]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_error_codes/src/error_codes/E0311.md
e73d5f16f9bf39fb2849b060fdb3505591f4cbd9
[rust.git] / compiler / rustc_error_codes / src / error_codes / E0311.md
1 This error occurs when there is insufficient information for the rust compiler
2 to prove that a type has a long enough lifetime.
3
4 Erroneous code example:
5
6 ```compile_fail,E0311
7 use std::borrow::BorrowMut;
8
9 trait NestedBorrowMut<U, V> {
10     fn nested_borrow_mut(&mut self) -> &mut V;
11 }
12
13 impl<T, U, V> NestedBorrowMut<U, V> for T
14 where
15     T: BorrowMut<U>,
16     U: BorrowMut<V>, // error: missing lifetime specifier
17 {
18     fn nested_borrow_mut(&mut self) -> &mut V {
19         self.borrow_mut().borrow_mut()
20     }
21 }
22 ```
23
24 Why doesn't this code compile? The problem has to do with Rust's rules for
25 lifetime elision in functions (Chapter 10.3 in the Rust book). One of the
26 inputs is a reference to `self`, so the compiler attempts to assign the
27 the same lifetime to the `&mut self` input and `&mut V` output to the
28 `nested_borrow_mut()` function. The problem is that there is no way for the
29 compiler to directly figure out how these two lifetimes are related in the
30 implementation of the function. We're implementing the `NextedBorrowMut`
31 trait for a type `T`, so the `&mut self` reference has the lifetime of `T`.
32 We know that `T` implements the `BorrowMut` trait returning a reference to `U`,
33 and that `U` implements the `BorrowMut` trait returning a reference to `V`.
34 The key is that we have not told the compiler that those two `U` lifetimes
35 are the same: for all it knows, we could be that the first `BorrowMut` trait
36 on `T` works with a lifetime `'a` and the second `BorrowMut` trait on `U`
37 works on a lifetime `'b`.
38
39 The fix here is to add explicit lifetime annotations that tell the compiler
40 that the lifetime of the output is in fact the same as the lifetime of the
41 input (`self`). There are three references involved, to objects of type `T`
42 (`self`), `U` (the intermediate type), and `V` (the return type). In the
43 working code below, we see that all have been given the same lifetime `'a`:
44 - `&'a mut self` in the function argument list for `T`
45 - `U: BorrowMut<V> + 'a` in the trait bounds for `U`
46 - `&'a mut V` in the function return for `V`.
47
48 The compiler can the check that the implementation of the
49 `nested_borrow_mut()` function satisfies these lifetimes. There are two
50 functions being called inside of `nested_borrow_mut()`, both of which are
51 the `borrow_mut()` function, which promises that the output lifetime is
52 the same as the input lifetime (see lifetime elision rules), which checks out.
53
54 ```
55 use std::borrow::BorrowMut;
56
57 trait NestedBorrowMut<'a, U, V> {
58     fn nested_borrow_mut(& 'a mut self) -> &'a mut V;
59 }
60
61 impl<'a, T, U, V> NestedBorrowMut<'a, U, V> for T
62 where
63     T: BorrowMut<U>,
64     U: BorrowMut<V> + 'a, // Adding lifetime specifier
65 {
66     fn nested_borrow_mut(&'a mut self) -> &'a mut V {
67         self.borrow_mut().borrow_mut()
68     }
69 }
70 ```