Skip to content

Commit b0255a1

Browse files
Suggest alternatives when trying to mutate a HashMap/BTreeMap via indexing
The error can be quite confusing to newcomers.
1 parent ee8c31e commit b0255a1

File tree

7 files changed

+57
-2
lines changed

7 files changed

+57
-2
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
12
use rustc_hir as hir;
23
use rustc_hir::Node;
34
use rustc_middle::hir::map::Map;
@@ -12,12 +13,11 @@ use rustc_middle::{
1213
};
1314
use rustc_span::source_map::DesugaringKind;
1415
use rustc_span::symbol::{kw, Symbol};
15-
use rustc_span::{BytePos, Span};
16+
use rustc_span::{sym, BytePos, Span};
1617

1718
use crate::diagnostics::BorrowedContentSource;
1819
use crate::MirBorrowckCtxt;
1920
use rustc_const_eval::util::collect_writes::FindAssignments;
20-
use rustc_errors::{Applicability, Diagnostic};
2121

2222
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2323
pub(crate) enum AccessKind {
@@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
614614
"trait `IndexMut` is required to modify indexed content, \
615615
but it is not implemented for `{ty}`",
616616
));
617+
self.suggest_map_index_mut_alternatives(ty, &mut err);
617618
}
618619
_ => (),
619620
}
@@ -627,6 +628,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
627628
self.buffer_error(err);
628629
}
629630

631+
fn suggest_map_index_mut_alternatives(
632+
&self,
633+
ty: Ty<'_>,
634+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
635+
) {
636+
let Some(adt) = ty.ty_adt_def() else { return };
637+
let did = adt.did();
638+
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
639+
|| self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
640+
{
641+
err.help(format!("to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API"));
642+
}
643+
}
644+
630645
/// User cannot make signature of a trait mutable without changing the
631646
/// trait. So we find if this error belongs to a trait and if so we move
632647
/// suggestion to the trait or disable it if it is out of scope of this crate

src/test/ui/borrowck/index-mut-help.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | map["peter"].clear();
55
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
66
|
77
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
8+
= help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
89

910
error[E0594]: cannot assign to data in an index of `HashMap<&str, String>`
1011
--> $DIR/index-mut-help.rs:12:5
@@ -13,6 +14,7 @@ LL | map["peter"] = "0".to_string();
1314
| ^^^^^^^^^^^^ cannot assign
1415
|
1516
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
17+
= help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
1618

1719
error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable
1820
--> $DIR/index-mut-help.rs:13:13
@@ -21,6 +23,7 @@ LL | let _ = &mut map["peter"];
2123
| ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
2224
|
2325
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>`
26+
= help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API
2427

2528
error: aborting due to 3 previous errors
2629

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::collections::BTreeMap;
2+
3+
fn main() {
4+
let mut map = BTreeMap::<u32, u32>::new();
5+
map[&0] = 1; //~ ERROR cannot assign
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0594]: cannot assign to data in an index of `BTreeMap<u32, u32>`
2+
--> $DIR/btreemap-index-mut.rs:5:5
3+
|
4+
LL | map[&0] = 1;
5+
| ^^^^^^^^^^^ cannot assign
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap<u32, u32>`
8+
= help: to modify a `BTreeMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0594`.
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::collections::HashMap;
2+
3+
fn main() {
4+
let mut map = HashMap::<u32, u32>::new();
5+
map[&0] = 1; //~ ERROR cannot assign
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0594]: cannot assign to data in an index of `HashMap<u32, u32>`
2+
--> $DIR/hashmap-index-mut.rs:5:5
3+
|
4+
LL | map[&0] = 1;
5+
| ^^^^^^^^^^^ cannot assign
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<u32, u32>`
8+
= help: to modify a `HashMap<u32, u32>`, use `.get_mut()`, `.insert()` or the entry API
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0594`.

src/test/ui/issues/issue-41726.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | things[src.as_str()].sort();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
66
|
77
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<String, Vec<String>>`
8+
= help: to modify a `HashMap<String, Vec<String>>`, use `.get_mut()`, `.insert()` or the entry API
89

910
error: aborting due to previous error
1011

0 commit comments

Comments
 (0)