@@ -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}`",
@@ -1196,7 +1196,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11961196 None
11971197 }
11981198 None => {
1199- if name != kw:: SelfLower {
1199+ let suggest_get_mut = self . suggest_get_mut_when_not_impl_index_mut (
1200+ local,
1201+ opt_assignment_rhs_span,
1202+ ) ;
1203+ if suggest_get_mut. is_some ( ) {
1204+ suggest_get_mut
1205+ } else if name != kw:: SelfLower {
12001206 suggest_ampmut (
12011207 self . infcx . tcx ,
12021208 local_decl. ty ,
@@ -1414,6 +1420,72 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
14141420 None => { }
14151421 }
14161422 }
1423+
1424+ /// check if the RHS is an overloaded index expression whose source type
1425+ /// doesn't implement `IndexMut`, if so, suggest using `.get_mut()` instead of `&mut`,
1426+ /// see issue #143732.
1427+ /// For example,
1428+ /// ```ignore (illustrative)
1429+ /// let mut map = HashMap::new();
1430+ /// let value = &map["key"];
1431+ /// ```
1432+ /// should be suggested to be
1433+ /// ```ignore (illustrative)
1434+ /// let mut map = HashMap::new();
1435+ /// let value = map["key"].get_mut().unwrap();
1436+ /// ```
1437+ fn suggest_get_mut_when_not_impl_index_mut (
1438+ & self ,
1439+ local : Local ,
1440+ opt_assignment_rhs_span : Option < Span > ,
1441+ ) -> Option < AmpMutSugg > {
1442+ self . find_assignments ( local)
1443+ . first ( )
1444+ . map ( |& location| {
1445+ if let Some ( mir:: Statement {
1446+ source_info : _,
1447+ kind : mir:: StatementKind :: Assign ( box ( _, mir:: Rvalue :: Ref ( _, _, place) ) ) ,
1448+ ..
1449+ } ) = self . body [ location. block ] . statements . get ( location. statement_index )
1450+ && let BorrowedContentSource :: OverloadedIndex ( ty, index_ty) =
1451+ self . borrowed_content_source ( place. as_ref ( ) )
1452+ && let Some ( index_mut_trait) = self . infcx . tcx . lang_items ( ) . index_mut_trait ( )
1453+ && !self
1454+ . infcx
1455+ . type_implements_trait (
1456+ index_mut_trait,
1457+ [ ty, index_ty] ,
1458+ self . infcx . param_env ,
1459+ )
1460+ . must_apply_modulo_regions ( )
1461+ {
1462+ if let Some ( rhs_span) = opt_assignment_rhs_span
1463+ && let Ok ( rhs_str) =
1464+ self . infcx . tcx . sess . source_map ( ) . span_to_snippet ( rhs_span)
1465+ && let Some ( content) = rhs_str. strip_prefix ( '&' )
1466+ && content. contains ( '[' )
1467+ && content. contains ( ']' )
1468+ {
1469+ let bracket_start = content. find ( '[' ) ?;
1470+ let bracket_end = content. rfind ( ']' ) ?;
1471+
1472+ if bracket_start < bracket_end {
1473+ let map_part = & content[ ..bracket_start] ;
1474+ let key_part = & content[ bracket_start + 1 ..bracket_end] ;
1475+
1476+ return Some ( AmpMutSugg {
1477+ has_sugg : true ,
1478+ span : rhs_span,
1479+ suggestion : format ! ( "{}.get_mut({}).unwrap()" , map_part, key_part) ,
1480+ additional : None ,
1481+ } ) ;
1482+ }
1483+ }
1484+ }
1485+ None
1486+ } )
1487+ . flatten ( )
1488+ }
14171489}
14181490
14191491struct BindingFinder {
0 commit comments