Skip to content

Commit fb65d75

Browse files
committed
Auto merge of #52788 - LukasKalbertodt:improve-index-mut-error, r=estebank
Add help message for missing `IndexMut` impl Code: ```rust let mut map = HashMap::new(); map.insert("peter", 23); map["peter"] = 27; ``` Before: ``` error[E0594]: cannot assign to immutable indexed content --> src/main.rs:7:5 | 7 | map["peter"] = 27; | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable ``` With this change (just the `help` was added): ``` error[E0594]: cannot assign to immutable indexed content --> index-error.rs:7:5 | 7 | map["peter"] = 27; | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for std::collections::HashMap<&str, i32> ``` --- Yesterday I did some pair programming with a Rust-beginner. We created a type and implemented `Index` for it. Trying to modify the value returned by the index operation returns in a rather vague error that was not very clear for the Rust beginner. So I tried to improve the situation. ## Notes/questions for reviewers: - Is the formulation OK like that? I'm fine with changing it. - Can we be absolutely sure that `IndexMut` is actually not implemented in the case my `help` message is added? I'm fairly sure myself, but there could be some cases I didn't think of. Also, I don't know the compiler very well, so I don't know what exactly certain enum variants are used for. - It would be nice to test if `IndexMut` is in fact not implemented for the type, but I couldn't figure out how to check that. If you think that additional check would be beneficial, could you tell me how to check if a trait is implemented? - Do you think I should change the error message instead of only adding an additional help message?
2 parents 8958ed6 + 24abef3 commit fb65d75

File tree

5 files changed

+99
-0
lines changed

5 files changed

+99
-0
lines changed

src/librustc_borrowck/borrowck/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
898898
}
899899
}
900900
}
901+
901902
db
902903
}
903904
BorrowViolation(euv::ClosureCapture(_)) => {
@@ -918,6 +919,28 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
918919
}
919920
};
920921

922+
// We add a special note about `IndexMut`, if the source of this error
923+
// is the fact that `Index` is implemented, but `IndexMut` is not. Needing
924+
// to implement two traits for "one operator" is not very intuitive for
925+
// many programmers.
926+
if err.cmt.note == mc::NoteIndex {
927+
let node_id = self.tcx.hir.hir_to_node_id(err.cmt.hir_id);
928+
let node = self.tcx.hir.get(node_id);
929+
930+
// This pattern probably always matches.
931+
if let hir_map::NodeExpr(
932+
hir::Expr { node: hir::ExprKind::Index(lhs, _), ..}
933+
) = node {
934+
let ty = self.tables.expr_ty(lhs);
935+
936+
db.help(&format!(
937+
"trait `IndexMut` is required to modify indexed content, but \
938+
it is not implemented for `{}`",
939+
ty
940+
));
941+
}
942+
}
943+
921944
self.note_and_explain_mutbl_error(&mut db, &err, &error_span);
922945
self.note_immutability_blame(
923946
&mut db,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0596]: cannot borrow data in a `&` reference as mutable
2+
--> $DIR/index-mut-help.rs:21:5
3+
|
4+
LL | map["peter"].clear(); //~ ERROR
5+
| ^^^^^^^^^^^^ cannot borrow as mutable
6+
7+
error[E0594]: cannot assign to data in a `&` reference
8+
--> $DIR/index-mut-help.rs:22:5
9+
|
10+
LL | map["peter"] = "0".to_string(); //~ ERROR
11+
| ^^^^^^^^^^^^ cannot assign
12+
13+
error[E0596]: cannot borrow data in a `&` reference as mutable
14+
--> $DIR/index-mut-help.rs:23:13
15+
|
16+
LL | let _ = &mut map["peter"]; //~ ERROR
17+
| ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
18+
19+
error: aborting due to 3 previous errors
20+
21+
Some errors occurred: E0594, E0596.
22+
For more information about an error, try `rustc --explain E0594`.
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// When mutably indexing a type that implements `Index` but not `IndexMut`, a
12+
// special 'help' message is added to the output.
13+
14+
15+
fn main() {
16+
use std::collections::HashMap;
17+
18+
let mut map = HashMap::new();
19+
map.insert("peter", "23".to_string());
20+
21+
map["peter"].clear(); //~ ERROR
22+
map["peter"] = "0".to_string(); //~ ERROR
23+
let _ = &mut map["peter"]; //~ ERROR
24+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0596]: cannot borrow immutable indexed content as mutable
2+
--> $DIR/index-mut-help.rs:21:5
3+
|
4+
LL | map["peter"].clear(); //~ ERROR
5+
| ^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
8+
9+
error[E0594]: cannot assign to immutable indexed content
10+
--> $DIR/index-mut-help.rs:22:5
11+
|
12+
LL | map["peter"] = "0".to_string(); //~ ERROR
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
14+
|
15+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
16+
17+
error[E0596]: cannot borrow immutable indexed content as mutable
18+
--> $DIR/index-mut-help.rs:23:18
19+
|
20+
LL | let _ = &mut map["peter"]; //~ ERROR
21+
| ^^^^^^^^^^^^ cannot borrow as mutable
22+
|
23+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
24+
25+
error: aborting due to 3 previous errors
26+
27+
Some errors occurred: E0594, E0596.
28+
For more information about an error, try `rustc --explain E0594`.

src/test/ui/issue-41726.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0596]: cannot borrow immutable indexed content as mutable
33
|
44
LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
55
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<std::string::String, std::vec::Vec<std::string::String>>`
68

79
error: aborting due to previous error
810

0 commit comments

Comments
 (0)