@@ -519,7 +519,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
519
519
but it is not implemented for `{ty}`",
520
520
) ) ;
521
521
}
522
- Some ( BorrowedContentSource :: OverloadedIndex ( ty) ) => {
522
+ Some ( BorrowedContentSource :: OverloadedIndex ( ty, _ ) ) => {
523
523
err. help ( format ! (
524
524
"trait `IndexMut` is required to modify indexed content, \
525
525
but it is not implemented for `{ty}`",
@@ -1176,6 +1176,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
1176
1176
self . body . source_info ( location) . span
1177
1177
}
1178
1178
} ) ;
1179
+
1179
1180
match opt_assignment_rhs_span. and_then ( |s| s. desugaring_kind ( ) ) {
1180
1181
// on for loops, RHS points to the iterator part
1181
1182
Some ( DesugaringKind :: ForLoop ) => {
@@ -1196,7 +1197,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
1196
1197
None
1197
1198
}
1198
1199
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 {
1200
1207
suggest_ampmut (
1201
1208
self . infcx . tcx ,
1202
1209
local_decl. ty ,
@@ -1414,6 +1421,66 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
1414
1421
None => { }
1415
1422
}
1416
1423
}
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
+ }
1417
1484
}
1418
1485
1419
1486
struct BindingFinder {
0 commit comments