Skip to content

Commit 062ab4f

Browse files
committed
add test for index mut suggestion causing borrow issue
1 parent 7b1ebf1 commit 062ab4f

2 files changed

Lines changed: 103 additions & 0 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// When mutably indexing a type that implements `Index` but not `IndexMut`, a
2+
// special 'help' message is added to the output.
3+
//
4+
// The suggestions have different requirements on the index type.
5+
// map[&idx] = val;
6+
// If idx is later used, it results in a borrow issue if both:
7+
// - the the suggestion that was chosen requires the idx, not a ref to it.
8+
// - idx's type is not Copy.
9+
//
10+
// For now, we suggest all options, regardless of the Copy-ness of the idx.
11+
use std::collections::HashMap;
12+
13+
/// With a copy type, subsequent reuse of idx is not an issue.
14+
fn copy_type() {
15+
// ===&str===, a copy type.
16+
17+
let mut map = HashMap::<&str, u32>::new();
18+
// earlier, peter is initialised with 22.
19+
// map["peter"] = 22; //ERROR
20+
map.insert("peter", 22);
21+
22+
// at some point, if we get a &str variable peter again
23+
let peter = "peter";
24+
// and we want to use it to update the map but still want to use it later?
25+
// map[&peter] = 23; // ERROR
26+
// we could insert again, and because &T are copy, we can use peter even if we use peter later.
27+
map.insert(peter, 23); // WORKS
28+
println!("my name is {peter}"); // WORKS because &str is Copy
29+
// and we could use a &&str too in this case, because &str:Borrow<&str> (because T:Borrow<T>)
30+
if let Some(val) = map.get_mut(&peter) {
31+
*val = 23;
32+
}; // WORKS
33+
println!("my name is {peter}"); // WORKS because &str is Copy
34+
// even a &str directly, (because rust auto borrows peter -> &peter ?)
35+
if let Some(val) = map.get_mut(peter) {
36+
*val = 24;
37+
}; // WORKS
38+
}
39+
40+
/// With a non-copy type, subsequent reuse of idx is an issue for `insert` and `entry`.
41+
fn non_copy_type_insert() {
42+
// ===STRING===, a non-copy type
43+
44+
let mut map = HashMap::<String, u32>::new();
45+
// earlier, peter is initialised with 22.
46+
// map[&"peter".to_string()] = 22; // ERROR cannot assign
47+
map.insert("peter".to_string(), 22);
48+
49+
// at some point, if we get a String variable peter again
50+
let peter = "peter".to_string();
51+
// and we want to use it to update the map but still want to use it later?
52+
// map[&peter] = 23; // ERROR cannot assign
53+
// we could insert again, but we cannot use peter after.
54+
map.insert(peter, 23); // WORKS
55+
println!("my name is {peter}"); //~ ERROR: borrow of moved value: `peter` [E0382]
56+
}
57+
58+
/// With a non-copy type, subsequent reuse of idx is not an issue for `get_mut`.
59+
fn non_copy_type_get_mut() {
60+
// ===STRING===, a non-copy type
61+
62+
let mut map = HashMap::<String, u32>::new();
63+
// earlier, peter is initialised with 22.
64+
// map["peter".to_string()] = 22; // ERROR cannot assign
65+
map.insert("peter".to_string(), 22);
66+
67+
// at some point, if we get a String variable peter again
68+
let peter = "peter".to_string();
69+
// and we want to use it to update the map but still want to use it later?
70+
// map[&peter] = 23; // ERROR cannot assign
71+
// we can use a &String in this case, so get_mut is always fine.
72+
if let Some(val) = map.get_mut(&peter) {
73+
*val = 23;
74+
}; // WORKS
75+
println!("my name is {peter}"); // WORKS
76+
// or a &str because String:Borrow<str>) and "peter" is &str.
77+
78+
if let Some(val) = map.get_mut("peter") {
79+
*val = 24;
80+
}; // WORKS
81+
println!("my name is {peter}"); // WORKS
82+
}
83+
84+
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0382]: borrow of moved value: `peter`
2+
--> $DIR/index-mut-suggest-borrow-issue.rs:55:27
3+
|
4+
LL | let peter = "peter".to_string();
5+
| ----- move occurs because `peter` has type `String`, which does not implement the `Copy` trait
6+
...
7+
LL | map.insert(peter, 23); // WORKS
8+
| ----- value moved here
9+
LL | println!("my name is {peter}");
10+
| ^^^^^ value borrowed here after move
11+
|
12+
help: consider cloning the value if the performance cost is acceptable
13+
|
14+
LL | map.insert(peter.clone(), 23); // WORKS
15+
| ++++++++
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)