@@ -519,7 +519,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
519519 but it is not implemented for `{ty}`",
520520 ) ) ;
521521 }
522- Some ( BorrowedContentSource :: OverloadedIndex ( ty) ) => {
522+ Some ( BorrowedContentSource :: OverloadedIndex ( ty, _ ) ) => {
523523 err. help ( format ! (
524524 "trait `IndexMut` is required to modify indexed content, \
525525 but it is not implemented for `{ty}`",
@@ -1176,6 +1176,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11761176 self . body . source_info ( location) . span
11771177 }
11781178 } ) ;
1179+
11791180 match opt_assignment_rhs_span. and_then ( |s| s. desugaring_kind ( ) ) {
11801181 // on for loops, RHS points to the iterator part
11811182 Some ( DesugaringKind :: ForLoop ) => {
@@ -1196,7 +1197,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11961197 None
11971198 }
11981199 None => {
1199- if name != kw:: SelfLower {
1200+ let suggest_get_mut = self . suggest_get_mut_when_not_impl_index_mut (
1201+ local,
1202+ opt_assignment_rhs_span,
1203+ ) ;
1204+ if suggest_get_mut. is_some ( ) {
1205+ suggest_get_mut
1206+ } else if name != kw:: SelfLower {
12001207 suggest_ampmut (
12011208 self . infcx . tcx ,
12021209 local_decl. ty ,
@@ -1414,6 +1421,66 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
14141421 None => { }
14151422 }
14161423 }
1424+
1425+ /// check if the RHS is an overloaded index expression from hashmap or btreemap,
1426+ /// if so, suggest using .get_mut() instead of &mut, see issue #143732
1427+ /// For example
1428+ /// ```text
1429+ /// let mut map = HashMap::new();
1430+ /// let value = &map["key"];
1431+ /// ```
1432+ fn suggest_get_mut_when_not_impl_index_mut (
1433+ & self ,
1434+ local : Local ,
1435+ opt_assignment_rhs_span : Option < Span > ,
1436+ ) -> Option < AmpMutSugg > {
1437+ self . find_assignments ( local)
1438+ . first ( )
1439+ . map ( |& location| {
1440+ if let Some ( mir:: Statement {
1441+ source_info : _,
1442+ kind : mir:: StatementKind :: Assign ( box ( _, mir:: Rvalue :: Ref ( _, _, place) ) ) ,
1443+ ..
1444+ } ) = self . body [ location. block ] . statements . get ( location. statement_index )
1445+ && let BorrowedContentSource :: OverloadedIndex ( ty, index_ty) =
1446+ self . borrowed_content_source ( place. as_ref ( ) )
1447+ && let Some ( index_mut_trait) = self . infcx . tcx . lang_items ( ) . index_mut_trait ( )
1448+ && !self
1449+ . infcx
1450+ . type_implements_trait (
1451+ index_mut_trait,
1452+ [ ty, index_ty] ,
1453+ self . infcx . param_env ,
1454+ )
1455+ . must_apply_modulo_regions ( )
1456+ {
1457+ if let Some ( rhs_span) = opt_assignment_rhs_span
1458+ && let Ok ( rhs_str) =
1459+ self . infcx . tcx . sess . source_map ( ) . span_to_snippet ( rhs_span)
1460+ && let Some ( content) = rhs_str. strip_prefix ( '&' )
1461+ && content. contains ( '[' )
1462+ && content. contains ( ']' )
1463+ {
1464+ let bracket_start = content. find ( '[' ) ?;
1465+ let bracket_end = content. rfind ( ']' ) ?;
1466+
1467+ if bracket_start < bracket_end {
1468+ let map_part = & content[ ..bracket_start] ;
1469+ let key_part = & content[ bracket_start + 1 ..bracket_end] ;
1470+
1471+ return Some ( AmpMutSugg {
1472+ has_sugg : true ,
1473+ span : rhs_span,
1474+ suggestion : format ! ( "{}.get_mut({}).unwrap()" , map_part, key_part) ,
1475+ additional : None ,
1476+ } ) ;
1477+ }
1478+ }
1479+ }
1480+ None
1481+ } )
1482+ . flatten ( )
1483+ }
14171484}
14181485
14191486struct BindingFinder {
0 commit comments