diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0ad4abbce2063..56721cc3f5c75 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,3 +1,4 @@ +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::Node; use rustc_middle::hir::map::Map; @@ -12,12 +13,11 @@ use rustc_middle::{ }; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{sym, BytePos, Span}; use crate::diagnostics::BorrowedContentSource; use crate::MirBorrowckCtxt; use rustc_const_eval::util::collect_writes::FindAssignments; -use rustc_errors::{Applicability, Diagnostic}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "trait `IndexMut` is required to modify indexed content, \ but it is not implemented for `{ty}`", )); + self.suggest_map_index_mut_alternatives(ty, &mut err); } _ => (), } @@ -627,6 +628,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.buffer_error(err); } + fn suggest_map_index_mut_alternatives( + &self, + ty: Ty<'_>, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + ) { + let Some(adt) = ty.ty_adt_def() else { return }; + let did = adt.did(); + if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did) + || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did) + { + err.help(format!("to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API")); + } + } + /// User cannot make signature of a trait mutable without changing the /// trait. So we find if this error belongs to a trait and if so we move /// suggestion to the trait or disable it if it is out of scope of this crate diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index 057c6ee15f36c..0ce60e3eb1db8 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -5,6 +5,7 @@ LL | map["peter"].clear(); | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` + = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API error[E0594]: cannot assign to data in an index of `HashMap<&str, String>` --> $DIR/index-mut-help.rs:12:5 @@ -13,6 +14,7 @@ LL | map["peter"] = "0".to_string(); | ^^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` + = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable --> $DIR/index-mut-help.rs:13:13 @@ -21,6 +23,7 @@ LL | let _ = &mut map["peter"]; | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` + = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API error: aborting due to 3 previous errors diff --git a/src/test/ui/btreemap/btreemap-index-mut.rs b/src/test/ui/btreemap/btreemap-index-mut.rs new file mode 100644 index 0000000000000..62972acab86eb --- /dev/null +++ b/src/test/ui/btreemap/btreemap-index-mut.rs @@ -0,0 +1,6 @@ +use std::collections::BTreeMap; + +fn main() { + let mut map = BTreeMap::::new(); + map[&0] = 1; //~ ERROR cannot assign +} diff --git a/src/test/ui/btreemap/btreemap-index-mut.stderr b/src/test/ui/btreemap/btreemap-index-mut.stderr new file mode 100644 index 0000000000000..260f710007426 --- /dev/null +++ b/src/test/ui/btreemap/btreemap-index-mut.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to data in an index of `BTreeMap` + --> $DIR/btreemap-index-mut.rs:5:5 + | +LL | map[&0] = 1; + | ^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap` + = help: to modify a `BTreeMap`, use `.get_mut()`, `.insert()` or the entry API + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/hashmap/hashmap-index-mut.rs b/src/test/ui/hashmap/hashmap-index-mut.rs new file mode 100644 index 0000000000000..98448e9d5f0f0 --- /dev/null +++ b/src/test/ui/hashmap/hashmap-index-mut.rs @@ -0,0 +1,6 @@ +use std::collections::HashMap; + +fn main() { + let mut map = HashMap::::new(); + map[&0] = 1; //~ ERROR cannot assign +} diff --git a/src/test/ui/hashmap/hashmap-index-mut.stderr b/src/test/ui/hashmap/hashmap-index-mut.stderr new file mode 100644 index 0000000000000..c72b380f4666d --- /dev/null +++ b/src/test/ui/hashmap/hashmap-index-mut.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to data in an index of `HashMap` + --> $DIR/hashmap-index-mut.rs:5:5 + | +LL | map[&0] = 1; + | ^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` + = help: to modify a `HashMap`, use `.get_mut()`, `.insert()` or the entry API + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-41726.stderr b/src/test/ui/issues/issue-41726.stderr index 22631e7c2a332..9c70ab7d9711d 100644 --- a/src/test/ui/issues/issue-41726.stderr +++ b/src/test/ui/issues/issue-41726.stderr @@ -5,6 +5,7 @@ LL | things[src.as_str()].sort(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` + = help: to modify a `HashMap>`, use `.get_mut()`, `.insert()` or the entry API error: aborting due to previous error