]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/lifetime-mismatch.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / nomicon / src / lifetime-mismatch.md
CommitLineData
8bb4bdeb 1# Limits of Lifetimes
c1a9b12d
SL
2
3Given the following code:
4
136023e0 5```rust,compile_fail
48663c56 6#[derive(Debug)]
c1a9b12d
SL
7struct Foo;
8
9impl Foo {
10 fn mutate_and_share(&mut self) -> &Self { &*self }
11 fn share(&self) {}
12}
13
14fn main() {
15 let mut foo = Foo;
16 let loan = foo.mutate_and_share();
17 foo.share();
48663c56 18 println!("{:?}", loan);
c1a9b12d
SL
19}
20```
21
48663c56
XL
22One might expect it to compile. We call `mutate_and_share`, which mutably
23borrows `foo` temporarily, but then returns only a shared reference. Therefore
24we would expect `foo.share()` to succeed as `foo` shouldn't be mutably borrowed.
c1a9b12d
SL
25
26However when we try to compile it:
27
28```text
0bf4aa26 29error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
48663c56 30 --> src/main.rs:12:5
0bf4aa26 31 |
48663c56 3211 | let loan = foo.mutate_and_share();
0bf4aa26 33 | --- mutable borrow occurs here
48663c56 3412 | foo.share();
0bf4aa26 35 | ^^^ immutable borrow occurs here
48663c56 3613 | println!("{:?}", loan);
c1a9b12d
SL
37```
38
39What happened? Well, we got the exact same reasoning as we did for
40[Example 2 in the previous section][ex2]. We desugar the program and we get
41the following:
42
136023e0 43<!-- ignore: desugared code -->
c1a9b12d
SL
44```rust,ignore
45struct Foo;
46
47impl Foo {
48 fn mutate_and_share<'a>(&'a mut self) -> &'a Self { &'a *self }
49 fn share<'a>(&'a self) {}
50}
51
52fn main() {
48663c56
XL
53 'b: {
54 let mut foo: Foo = Foo;
55 'c: {
56 let loan: &'c Foo = Foo::mutate_and_share::<'c>(&'c mut foo);
57 'd: {
58 Foo::share::<'d>(&'d foo);
59 }
60 println!("{:?}", loan);
61 }
c1a9b12d
SL
62 }
63}
64```
65
66The lifetime system is forced to extend the `&mut foo` to have lifetime `'c`,
48663c56 67due to the lifetime of `loan` and `mutate_and_share`'s signature. Then when we
c1a9b12d
SL
68try to call `share`, and it sees we're trying to alias that `&'c mut foo` and
69blows up in our face!
70
71This program is clearly correct according to the reference semantics we actually
72care about, but the lifetime system is too coarse-grained to handle that.
73
136023e0 74## Improperly reduced borrows
48663c56 75
6a06907d 76The following code fails to compile, because Rust doesn't understand that the borrow
48663c56
XL
77is no longer needed and conservatively falls back to using a whole scope for it.
78This will eventually get fixed.
79
136023e0 80```rust,compile_fail
48663c56 81# use std::collections::HashMap;
48663c56
XL
82# use std::hash::Hash;
83fn get_default<'m, K, V>(map: &'m mut HashMap<K, V>, key: K) -> &'m mut V
84where
85 K: Clone + Eq + Hash,
86 V: Default,
87{
88 match map.get_mut(&key) {
89 Some(value) => value,
90 None => {
91 map.insert(key.clone(), V::default());
92 map.get_mut(&key).unwrap()
93 }
94 }
95}
96```
c1a9b12d 97
6a06907d
XL
98Because of the lifetime restrictions imposed, `&mut map`'s lifetime
99overlaps other mutable borrows, resulting in a compile error:
100
101```text
102error[E0499]: cannot borrow `*map` as mutable more than once at a time
103 --> src/main.rs:12:13
104 |
1054 | fn get_default<'m, K, V>(map: &'m mut HashMap<K, V>, key: K) -> &'m mut V
106 | -- lifetime `'m` defined here
107...
1089 | match map.get_mut(&key) {
109 | - --- first mutable borrow occurs here
110 | _____|
111 | |
11210 | | Some(value) => value,
11311 | | None => {
11412 | | map.insert(key.clone(), V::default());
115 | | ^^^ second mutable borrow occurs here
11613 | | map.get_mut(&key).unwrap()
11714 | | }
11815 | | }
119 | |_____- returning this value requires that `*map` is borrowed for `'m`
120```
121
b039eaaf 122[ex2]: lifetimes.html#example-aliasing-a-mutable-reference