diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 511fb2a9b3be..00317b376e8c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, BindingMode, ByRef, Node}; +use rustc_hir::{self as hir, BindingMode, ByRef, Expr, Node}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::visit::PlaceContext; @@ -669,7 +669,9 @@ struct SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> { err: &'a mut Diag<'infcx>, ty: Ty<'tcx>, suggested: bool, + infcx: &'a rustc_infer::infer::InferCtxt<'tcx>, } + impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { hir::intravisit::walk_stmt(self, stmt); @@ -680,60 +682,166 @@ fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { return; } }; + + // Because of TypeChecking and indexing, we know: index is &Q + // with K: Eq + Hash + Borrow, + // with Q: Eq + Hash + ?Sized, + // + // which fulfill the requirements of `get_mut`. If Q=K or Q=&{n}K, the requirements + // of `entry` and `insert` are fulfilled too after dereferencing. If K is not + // copy, a subsequent `clone` call may be needed. + + /// Taken straight from https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.peel_hir_ty_refs.html + /// Adapted to mid using https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs + /// Simplified to counting only + /// Peels off all references on the type. Returns the number of references + /// removed. + fn count_ty_refs<'tcx>(mut ty: Ty<'tcx>) -> usize { + let mut count = 0; + while let ty::Ref(_, inner_ty, _) = ty.kind() { + ty = *inner_ty; + count += 1; + } + count + } + + /// Try to strip `n` `&` reference from an expression. + /// If the expression does not have enough leading `&`, return an Error + /// containing a count of the successfully stripped ones and the stripped + /// expression. + fn strip_n_refs<'a, 'b>( + mut expr: &'a Expr<'b>, + n: usize, + ) -> Result<&'a Expr<'b>, (usize, &'a Expr<'b>)> { + for count in 0..n { + match expr { + Expr { + kind: ExprKind::AddrOf(hir::BorrowKind::Ref, _, inner), + .. + } => expr = inner, + _ => return Err((count, expr)), + } + } + Ok(expr) + } + + // we know ty is a map, with a key type at walk distance 2. + let key_ty = self.ty.walk().nth(1).unwrap().expect_ty(); + if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind && let hir::ExprKind::Index(val, index, _) = place.kind && (expr.span == self.assign_span || place.span == self.assign_span) { // val[index] = rv; - // ---------- place - self.err.multipart_suggestions( - format!( - "use `.insert()` to insert a value into a `{}`, `.get_mut()` \ - to modify it, or the entry API for more flexibility", - self.ty, - ), - vec![ + let index_ty = + self.infcx.tcx.typeck(val.hir_id.owner.def_id).expr_ty(index); + + let (borrowed_prefix, borrowed_index); + + // only suggest `insert` and `entry` if index is of type K or &{n}K or *{n}K (when there is a Borrow impl for this case). + // We use `peel_refs` because borrow lifetimes may differ in both index and + // key. I.e, if they are of the same base type: + if index_ty.peel_refs() == key_ty.peel_refs() { + let (index_refs, key_refs) = + (count_ty_refs(index_ty), count_ty_refs(key_ty)); + + let (deref_prefix, deref_index) = if index_refs >= key_refs { + // index is &{n}K + strip_n_refs(index, index_refs - key_refs) + .map(|val| ("".to_string(), val)) + .unwrap_or_else(|(depth, val)| { + ( + if key_refs == 0 { + "*".repeat( + (index_refs-key_refs).checked_sub(depth).expect("return depth from strip_n_refs should be smaller than the input") + ) + } else { + String::new() //if key K is a ref, autoderef finish this for us. + }, + val, + ) + }) + } else { + // in this case the minimal ref addition works for all subcases + ("&".repeat(key_refs - index_refs), index) + }; + + self.err.multipart_suggestion( + format!("use `.insert()` to insert a value into a `{}`", self.ty), vec![ - // val.insert(index, rv); + // val.insert({deref_prefix}{deref_index}, rv); ( - val.span.shrink_to_hi().with_hi(index.span.lo()), - ".insert(".to_string(), + val.span.shrink_to_hi().with_hi(deref_index.span.lo()), + format!(".insert({deref_prefix}"), ), ( - index.span.shrink_to_hi().with_hi(rv.span.lo()), + deref_index.span.shrink_to_hi().with_hi(rv.span.lo()), ", ".to_string(), ), (rv.span.shrink_to_hi(), ")".to_string()), ], + Applicability::MaybeIncorrect, + ); + self.err.multipart_suggestion( + format!( + "use the entry API to modify a `{}` for more flexibility", + self.ty + ), vec![ - // if let Some(v) = val.get_mut(index) { *v = rv; } - (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()), - ( - val.span.shrink_to_hi().with_hi(index.span.lo()), - ".get_mut(".to_string(), - ), - ( - index.span.shrink_to_hi().with_hi(place.span.hi()), - ") { *val".to_string(), - ), - (rv.span.shrink_to_hi(), "; }".to_string()), - ], - vec![ - // let x = val.entry(index).or_insert(rv); + // let x = val.entry({deref_prefix}{deref_index}).insert_entry(rv); (val.span.shrink_to_lo(), "let val = ".to_string()), ( - val.span.shrink_to_hi().with_hi(index.span.lo()), - ".entry(".to_string(), + val.span.shrink_to_hi().with_hi(deref_index.span.lo()), + format!(".entry({deref_prefix}"), ), ( - index.span.shrink_to_hi().with_hi(rv.span.lo()), - ").or_insert(".to_string(), + deref_index.span.shrink_to_hi().with_hi(rv.span.lo()), + ").insert_entry(".to_string(), ), (rv.span.shrink_to_hi(), ")".to_string()), ], + Applicability::MaybeIncorrect, + ); + + // we can make the next suggestions nicer by stripping as many leading `&` as + // we can, autoderef will do the rest + (borrowed_prefix, borrowed_index) = ( + String::new(), + if index_refs > key_refs { + strip_n_refs(index, index_refs - key_refs - 1) + .unwrap_or_else(|(_depth, val)| val) + // even if we tried to strip more, we can stop there thanks to autoderef + } else { + // when the diff is negative or zero, we already are in the index=&Q case. + index + }, + ); + } else { + (borrowed_prefix, borrowed_index) = (String::new(), index) + } + // in all cases, suggest get_mut because K:Borrow or Q:Borrow as a + // requirement of indexing. + self.err.multipart_suggestion( + format!( + "use `.get_mut()` to modify an existing key in a `{}`", + self.ty, + ), + vec![ + // if let Some(v) = val.get_mut({borrowed_prefix}{borrowed_index}) { *v = rv; } + (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()), + ( + val.span.shrink_to_hi().with_hi(borrowed_index.span.lo()), + format!(".get_mut({borrowed_prefix}"), + ), + ( + borrowed_index.span.shrink_to_hi().with_hi(place.span.hi()), + ") { *val".to_string(), + ), + (rv.span.shrink_to_hi(), "; }".to_string()), ], - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); + self.suggested = true; } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind && let hir::ExprKind::Index(val, index, _) = receiver.kind @@ -769,6 +877,7 @@ fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { err, ty, suggested: false, + infcx: self.infcx, }; v.visit_body(&body); if !v.suggested { diff --git a/tests/ui/borrowck/index-mut-help.stderr b/tests/ui/borrowck/index-mut-help.stderr index 6c3bd0df20b2..fc8d02b0f0b4 100644 --- a/tests/ui/borrowck/index-mut-help.stderr +++ b/tests/ui/borrowck/index-mut-help.stderr @@ -18,16 +18,20 @@ 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: use `.insert()` to insert a value into a `HashMap<&str, String>`, `.get_mut()` to modify it, or the entry API for more flexibility +help: use `.insert()` to insert a value into a `HashMap<&str, String>` | LL - map["peter"] = "0".to_string(); LL + map.insert("peter", "0".to_string()); | -LL - map["peter"] = "0".to_string(); -LL + if let Some(val) = map.get_mut("peter") { *val = "0".to_string(); }; +help: use the entry API to modify a `HashMap<&str, String>` for more flexibility | LL - map["peter"] = "0".to_string(); -LL + let val = map.entry("peter").or_insert("0".to_string()); +LL + let val = map.entry("peter").insert_entry("0".to_string()); + | +help: use `.get_mut()` to modify an existing key in a `HashMap<&str, String>` + | +LL - map["peter"] = "0".to_string(); +LL + if let Some(val) = map.get_mut("peter") { *val = "0".to_string(); }; | error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable diff --git a/tests/ui/borrowck/index-mut-help2.rs b/tests/ui/borrowck/index-mut-help2.rs new file mode 100644 index 000000000000..0447cb1c8abb --- /dev/null +++ b/tests/ui/borrowck/index-mut-help2.rs @@ -0,0 +1,176 @@ +// When mutably indexing a type that implements `Index` but not `IndexMut`, a +// special 'help' message is added to the output. +// ... Except when it is not! +use std::borrow::Borrow; +use std::collections::HashMap; + +#[derive(Hash, Eq, PartialEq)] +struct A {} +#[derive(Hash, Eq, PartialEq, Copy, Clone)] +struct ACopy {} +#[derive(Hash, Eq, PartialEq)] +struct B {} +#[derive(Hash, Eq, PartialEq)] +struct C {} +#[derive(Hash, Eq, PartialEq)] +struct D {} + +impl Borrow for D { + fn borrow(&self) -> &C { + &C {} + } +} + +/// In this test the key is a A type. +fn test_a_index() { + let mut map = HashMap::::new(); + + let index = &&&&&A {}; + // index gets autodereferenced + map[index] = 23; //~ ERROR E0594 + map[&&&&&&&&index] = 23; //~ ERROR E0594 +} +/// In this test the key is a A type. Auto-dereferencing to &A works but dereferencing to A need +/// the exact amount of `*` +fn test_a_2() { + let mut map = HashMap::::new(); + + let index = &&&&&A {}; + // complete dereferencing needs to be exact + map.insert(*index, 23); //~ ERROR E0308 + // index gets autodereferenced + if let Some(val) = map.get_mut(index) { + *val = 23; + } // passes +} +/// In this test the key is a A type. Could not be merged with 2 because compiler only shows error +/// 0308 +fn test_a_3() { + let mut map = HashMap::::new(); + + let index = &&&&&A {}; + // A does not implement Copy so a Clone might be required + map.insert(*****index, 23); //~ ERROR E0507 +} + +/// In this test the key is a ACopy type. +fn test_acopy_index() { + let mut map = HashMap::::new(); + + let index = &&&&&ACopy {}; + // index gets autodereferenced + map[index] = 23; //~ ERROR E0594 +} +/// In this test the key is a ACopy type. Auto-dereferencing to &A works but dereferencing to A +/// need the exact amount of `*`. +fn test_acopy_2() { + let mut map = HashMap::::new(); + + let index = &&&&&ACopy {}; + // complete dereferencing needs to be exact + map.insert(*index, 23); //~ ERROR E0308 + + // index gets autodereferenced + if let Some(val) = map.get_mut(index) { + *val = 23; + } // passes +} +/// In this test the key is a ACopy type. Could not be merged with 2 because compiler only shows +/// error 0308 +fn test_acopy_3() { + let mut map = HashMap::::new(); + + let index = &&&&&ACopy {}; + map.insert(*****index, 23); // no E057 error in this case because ACopy is Copy +} + +/// In this test the key type is B-reference. The autodereferencing does not work in this case for +/// both for the map[index] part and `get_mut` call. +/// This leads to E0277 errors. +fn test_b() { + let mut map = HashMap::<&B, u32>::new(); + + let index = &&&&&B {}; + // index does NOT get autorederefenced + map[index] = 23; //~ ERROR E0277 + + // index does NOT get autorederefenced + if let Some(val) = map.get_mut(index) { //~ ERROR E0277 + *val = 23; + } + if let Some(val) = map.get_mut(***index) { + *val = 23; + } // passes +} + +/// In this test the key type is C. +/// The `Borrow for D` implementation changes nothing here, same error as for test_a. +fn test_c() { + let mut map = HashMap::::new(); + + let index = &&&&&C {}; + // index gets autodereferenced + map[index] = 23; //~ ERROR E0594 + + // index gets autodereferenced + if let Some(val) = map.get_mut(index) { + *val = 23; + } // passes +} + +/// In this test the key type is D. The `Borrow for D` implementation seems to prevent +/// autodereferencing. +/// The autodereferencing does not work in this case for both for the map[index] part and `get_mut` +/// call. +/// This leads to E0277 errors. +fn test_d() { + let mut map = HashMap::::new(); + + let index = &&&&&D {}; + // index does NOT get autorederefenced + map[index] = 23; //~ ERROR E0277 + + // index does NOT get autorederefenced + if let Some(val) = map.get_mut(index) {//~ ERROR E0277 + *val = 23; + } + if let Some(val) = map.get_mut(****index) { + *val = 23; + } // passes +} + +#[derive(Hash, PartialEq, Eq)] +struct S {} +// it is possible to have a Borrowed version of a type be of the same type but less borrowed. +// here, a borrowed version of `&&&S` is `&S`. +impl Borrow for &&&S { + fn borrow(&self) -> &S { + self + } +} + +/// In this test, the index type is the same base type as the key, but because of a peculiar Borrow +/// impl, it is of a lesser ref depth than the key. +/// There are some E0716 errors that result from the suggestion, but they already have diagnostics +fn test_s() { + let mut map = HashMap::<&&&S, usize>::new(); + let index = &S{}; + map[index] = 12; //~ ERROR E0594 + map.insert(&&index, 12); //~ ERROR E0716 + let val = map.entry(&&index).insert_entry(12); //~ ERROR E0716 + if let Some(val) = map.get_mut(index) { + *val = 12; + }; +} + +fn main() { + test_a_index(); + test_a_2(); + test_a_3(); + test_acopy_index(); + test_acopy_2(); + test_acopy_3(); + test_b(); + test_c(); + test_d(); +} diff --git a/tests/ui/borrowck/index-mut-help2.stderr b/tests/ui/borrowck/index-mut-help2.stderr new file mode 100644 index 000000000000..44dd966cfd6a --- /dev/null +++ b/tests/ui/borrowck/index-mut-help2.stderr @@ -0,0 +1,244 @@ +error[E0308]: mismatched types + --> $DIR/index-mut-help2.rs:40:16 + | +LL | map.insert(*index, 23); + | ------ ^^^^^^ expected `A`, found `&&&&A` + | | + | arguments to this method are incorrect + | +note: method defined here + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/index-mut-help2.rs:71:16 + | +LL | map.insert(*index, 23); + | ------ ^^^^^^ expected `ACopy`, found `&&&&ACopy` + | | + | arguments to this method are incorrect + | +note: method defined here + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +help: consider dereferencing the borrow + | +LL | map.insert(*****index, 23); + | ++++ + +error[E0277]: the trait bound `&B: Borrow<&&&&B>` is not satisfied + --> $DIR/index-mut-help2.rs:95:9 + | +LL | map[index] = 23; + | ^^^^^ the trait `Borrow<&&&&B>` is not implemented for `&B` + | + = note: required for `HashMap<&B, u32>` to implement `Index<&&&&&B>` + +error[E0277]: the trait bound `&B: Borrow<&&&&B>` is not satisfied + --> $DIR/index-mut-help2.rs:98:36 + | +LL | if let Some(val) = map.get_mut(index) { + | ------- ^^^^^ the trait `Borrow<&&&&B>` is not implemented for `&B` + | | + | required by a bound introduced by this call + | +note: required by a bound in `HashMap::::get_mut` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + +error[E0277]: the trait bound `D: Borrow<&&&&D>` is not satisfied + --> $DIR/index-mut-help2.rs:131:9 + | +LL | map[index] = 23; + | ^^^^^ unsatisfied trait bound + | +help: the trait `Borrow<&&&&D>` is not implemented for `D` + but trait `Borrow` is implemented for it + --> $DIR/index-mut-help2.rs:18:1 + | +LL | impl Borrow for D { + | ^^^^^^^^^^^^^^^^^^^^ + = help: for that trait implementation, expected `C`, found `&&&&D` + = note: required for `HashMap` to implement `Index<&&&&&D>` + +error[E0277]: the trait bound `D: Borrow<&&&&D>` is not satisfied + --> $DIR/index-mut-help2.rs:134:36 + | +LL | if let Some(val) = map.get_mut(index) { + | ------- ^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the trait `Borrow<&&&&D>` is not implemented for `D` + but trait `Borrow` is implemented for it + --> $DIR/index-mut-help2.rs:18:1 + | +LL | impl Borrow for D { + | ^^^^^^^^^^^^^^^^^^^^ + = help: for that trait implementation, expected `C`, found `&&&&D` +note: required by a bound in `HashMap::::get_mut` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + +error[E0594]: cannot assign to data in an index of `HashMap` + --> $DIR/index-mut-help2.rs:30:5 + | +LL | map[index] = 23; + | ^^^^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` +help: use `.insert()` to insert a value into a `HashMap` + | +LL - map[index] = 23; +LL + map.insert(*****index, 23); + | +help: use the entry API to modify a `HashMap` for more flexibility + | +LL - map[index] = 23; +LL + let val = map.entry(*****index).insert_entry(23); + | +help: use `.get_mut()` to modify an existing key in a `HashMap` + | +LL - map[index] = 23; +LL + if let Some(val) = map.get_mut(index) { *val = 23; }; + | + +error[E0594]: cannot assign to data in an index of `HashMap` + --> $DIR/index-mut-help2.rs:31:5 + | +LL | map[&&&&&&&&index] = 23; + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` +help: use `.insert()` to insert a value into a `HashMap` + | +LL - map[&&&&&&&&index] = 23; +LL + map.insert(*****index, 23); + | +help: use the entry API to modify a `HashMap` for more flexibility + | +LL - map[&&&&&&&&index] = 23; +LL + let val = map.entry(*****index).insert_entry(23); + | +help: use `.get_mut()` to modify an existing key in a `HashMap` + | +LL - map[&&&&&&&&index] = 23; +LL + if let Some(val) = map.get_mut(index) { *val = 23; }; + | + +error[E0507]: cannot move out of `*****index` which is behind a shared reference + --> $DIR/index-mut-help2.rs:53:16 + | +LL | map.insert(*****index, 23); + | ^^^^^^^^^^ move occurs because `*****index` has type `A`, which does not implement the `Copy` trait + | +note: if `A` implemented `Clone`, you could clone the value + --> $DIR/index-mut-help2.rs:8:1 + | +LL | struct A {} + | ^^^^^^^^ consider implementing `Clone` for this type +... +LL | map.insert(*****index, 23); + | ---------- you could clone this value + +error[E0594]: cannot assign to data in an index of `HashMap` + --> $DIR/index-mut-help2.rs:62:5 + | +LL | map[index] = 23; + | ^^^^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` +help: use `.insert()` to insert a value into a `HashMap` + | +LL - map[index] = 23; +LL + map.insert(*****index, 23); + | +help: use the entry API to modify a `HashMap` for more flexibility + | +LL - map[index] = 23; +LL + let val = map.entry(*****index).insert_entry(23); + | +help: use `.get_mut()` to modify an existing key in a `HashMap` + | +LL - map[index] = 23; +LL + if let Some(val) = map.get_mut(index) { *val = 23; }; + | + +error[E0594]: cannot assign to data in an index of `HashMap` + --> $DIR/index-mut-help2.rs:113:5 + | +LL | map[index] = 23; + | ^^^^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` +help: use `.insert()` to insert a value into a `HashMap` + | +LL - map[index] = 23; +LL + map.insert(*****index, 23); + | +help: use the entry API to modify a `HashMap` for more flexibility + | +LL - map[index] = 23; +LL + let val = map.entry(*****index).insert_entry(23); + | +help: use `.get_mut()` to modify an existing key in a `HashMap` + | +LL - map[index] = 23; +LL + if let Some(val) = map.get_mut(index) { *val = 23; }; + | + +error[E0594]: cannot assign to data in an index of `HashMap<&&&S, usize>` + --> $DIR/index-mut-help2.rs:158:5 + | +LL | map[index] = 12; + | ^^^^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&&&S, usize>` +help: use `.insert()` to insert a value into a `HashMap<&&&S, usize>` + | +LL - map[index] = 12; +LL + map.insert(&&index, 12); + | +help: use the entry API to modify a `HashMap<&&&S, usize>` for more flexibility + | +LL - map[index] = 12; +LL + let val = map.entry(&&index).insert_entry(12); + | +help: use `.get_mut()` to modify an existing key in a `HashMap<&&&S, usize>` + | +LL - map[index] = 12; +LL + if let Some(val) = map.get_mut(index) { *val = 12; }; + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/index-mut-help2.rs:159:17 + | +LL | map.insert(&&index, 12); + | ^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | let val = map.entry(&&index).insert_entry(12); + | --- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = &index; +LL ~ map.insert(&binding, 12); + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/index-mut-help2.rs:160:26 + | +LL | let val = map.entry(&&index).insert_entry(12); + | ^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | if let Some(val) = map.get_mut(index) { + | --- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = &index; +LL ~ let val = map.entry(&binding).insert_entry(12); + | + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0277, E0308, E0507, E0594, E0716. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/collections/btreemap/btreemap-index-mut-2.stderr b/tests/ui/collections/btreemap/btreemap-index-mut-2.stderr index 74a8aaf8aee9..bb82ef43ff11 100644 --- a/tests/ui/collections/btreemap/btreemap-index-mut-2.stderr +++ b/tests/ui/collections/btreemap/btreemap-index-mut-2.stderr @@ -5,17 +5,21 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap` -help: use `.insert()` to insert a value into a `BTreeMap`, `.get_mut()` to modify it, or the entry API for more flexibility +help: use `.insert()` to insert a value into a `BTreeMap` | LL - map[&0] = 1; -LL + map.insert(&0, 1); +LL + map.insert(0, 1); + | +help: use the entry API to modify a `BTreeMap` for more flexibility + | +LL - map[&0] = 1; +LL + let val = map.entry(0).insert_entry(1); + | +help: use `.get_mut()` to modify an existing key in a `BTreeMap` | LL - map[&0] = 1; LL + if let Some(val) = map.get_mut(&0) { *val = 1; }; | -LL - map[&0] = 1; -LL + let val = map.entry(&0).or_insert(1); - | error: aborting due to 1 previous error diff --git a/tests/ui/collections/btreemap/btreemap-index-mut.stderr b/tests/ui/collections/btreemap/btreemap-index-mut.stderr index e8850ed2a174..e09ede34db56 100644 --- a/tests/ui/collections/btreemap/btreemap-index-mut.stderr +++ b/tests/ui/collections/btreemap/btreemap-index-mut.stderr @@ -5,17 +5,21 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap` -help: use `.insert()` to insert a value into a `BTreeMap`, `.get_mut()` to modify it, or the entry API for more flexibility +help: use `.insert()` to insert a value into a `BTreeMap` | LL - map[&0] = 1; -LL + map.insert(&0, 1); +LL + map.insert(0, 1); + | +help: use the entry API to modify a `BTreeMap` for more flexibility + | +LL - map[&0] = 1; +LL + let val = map.entry(0).insert_entry(1); + | +help: use `.get_mut()` to modify an existing key in a `BTreeMap` | LL - map[&0] = 1; LL + if let Some(val) = map.get_mut(&0) { *val = 1; }; | -LL - map[&0] = 1; -LL + let val = map.entry(&0).or_insert(1); - | error: aborting due to 1 previous error diff --git a/tests/ui/collections/hashmap/hashmap-index-mut.stderr b/tests/ui/collections/hashmap/hashmap-index-mut.stderr index e8b22350c59d..bb291367dd43 100644 --- a/tests/ui/collections/hashmap/hashmap-index-mut.stderr +++ b/tests/ui/collections/hashmap/hashmap-index-mut.stderr @@ -5,17 +5,21 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` -help: use `.insert()` to insert a value into a `HashMap`, `.get_mut()` to modify it, or the entry API for more flexibility +help: use `.insert()` to insert a value into a `HashMap` | LL - map[&0] = 1; -LL + map.insert(&0, 1); +LL + map.insert(0, 1); + | +help: use the entry API to modify a `HashMap` for more flexibility + | +LL - map[&0] = 1; +LL + let val = map.entry(0).insert_entry(1); + | +help: use `.get_mut()` to modify an existing key in a `HashMap` | LL - map[&0] = 1; LL + if let Some(val) = map.get_mut(&0) { *val = 1; }; | -LL - map[&0] = 1; -LL + let val = map.entry(&0).or_insert(1); - | error: aborting due to 1 previous error