@@ -1176,6 +1176,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11761176 self . body . source_info ( location) . span
11771177 }
11781178 } ) ;
1179+
1180+ let is_rhs_map_index = self . is_rhs_index_from_hashmap_or_btreemap ( local) ;
11791181 match opt_assignment_rhs_span. and_then ( |s| s. desugaring_kind ( ) ) {
11801182 // on for loops, RHS points to the iterator part
11811183 Some ( DesugaringKind :: ForLoop ) => {
@@ -1203,6 +1205,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12031205 decl_span,
12041206 opt_assignment_rhs_span,
12051207 opt_ty_info,
1208+ is_rhs_map_index,
12061209 )
12071210 } else {
12081211 match local_decl. local_info ( ) {
@@ -1226,6 +1229,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
12261229 decl_span,
12271230 opt_assignment_rhs_span,
12281231 opt_ty_info,
1232+ is_rhs_map_index,
12291233 ) ,
12301234 }
12311235 }
@@ -1414,6 +1418,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
14141418 None => { }
14151419 }
14161420 }
1421+
1422+ /// check if the RHS is an overloaded index expression from hashmap or btreemap,
1423+ /// if so, suggest using .get_mut() instead of &mut, see issue #143732
1424+ /// For example
1425+ /// ```text
1426+ /// let mut map = HashMap::new();
1427+ /// let value = &map["key"];
1428+ /// ```
1429+ fn is_rhs_index_from_hashmap_or_btreemap ( & self , local : Local ) -> bool {
1430+ self . find_assignments ( local)
1431+ . first ( )
1432+ . map ( |& location| {
1433+ if let Some ( mir:: Statement {
1434+ source_info : _,
1435+ kind : mir:: StatementKind :: Assign ( box ( _, mir:: Rvalue :: Ref ( _, _, place) ) ) ,
1436+ ..
1437+ } ) = self . body [ location. block ] . statements . get ( location. statement_index )
1438+ && let BorrowedContentSource :: OverloadedIndex ( ty) =
1439+ self . borrowed_content_source ( place. as_ref ( ) )
1440+ && let Some ( def) = ty. ty_adt_def ( )
1441+ && ( self . infcx . tcx . is_diagnostic_item ( sym:: HashMap , def. did ( ) )
1442+ || self . infcx . tcx . is_diagnostic_item ( sym:: BTreeMap , def. did ( ) ) )
1443+ {
1444+ true
1445+ } else {
1446+ false
1447+ }
1448+ } )
1449+ . unwrap_or ( false )
1450+ }
14171451}
14181452
14191453struct BindingFinder {
@@ -1507,6 +1541,7 @@ fn suggest_ampmut<'tcx>(
15071541 decl_span : Span ,
15081542 opt_assignment_rhs_span : Option < Span > ,
15091543 opt_ty_info : Option < Span > ,
1544+ is_rhs_map_index : bool ,
15101545) -> Option < AmpMutSugg > {
15111546 // if there is a RHS and it starts with a `&` from it, then check if it is
15121547 // mutable, and if not, put suggest putting `mut ` to make it mutable.
@@ -1553,6 +1588,28 @@ fn suggest_ampmut<'tcx>(
15531588 // if the reference is already mutable then there is nothing we can do
15541589 // here.
15551590 if !is_mut {
1591+ // If this is an overloaded index expression, suggest using .get_mut() instead of &mut
1592+ if is_rhs_map_index {
1593+ // Try to extract the expression from &expr[key] to suggest expr.get_mut(key).unwrap()
1594+ let content = rhs_str. strip_prefix ( '&' ) ?;
1595+ if content. contains ( '[' ) && content. contains ( ']' ) {
1596+ let bracket_start = content. find ( '[' ) ?;
1597+ let bracket_end = content. rfind ( ']' ) ?;
1598+
1599+ if bracket_start < bracket_end {
1600+ let map_part = & content[ ..bracket_start] ;
1601+ let key_part = & content[ bracket_start + 1 ..bracket_end] ;
1602+
1603+ return Some ( AmpMutSugg {
1604+ has_sugg : true ,
1605+ span : rhs_span,
1606+ suggestion : format ! ( "{}.get_mut({}).unwrap()" , map_part, key_part) ,
1607+ additional : None ,
1608+ } ) ;
1609+ }
1610+ }
1611+ }
1612+
15561613 // shrink the span to just after the `&` in `&variable`
15571614 let span = rhs_span. with_lo ( rhs_span. lo ( ) + BytePos ( 1 ) ) . shrink_to_lo ( ) ;
15581615
0 commit comments