@@ -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}`",
@@ -1196,7 +1196,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
1196
1196
None
1197
1197
}
1198
1198
None => {
1199
- if name != kw:: SelfLower {
1199
+ let ( should_suggest_ref_mut, suggest_get_mut) =
1200
+ self . suggest_get_mut_or_ref_mut ( local, opt_assignment_rhs_span) ;
1201
+ if !should_suggest_ref_mut {
1202
+ suggest_get_mut
1203
+ } else if name != kw:: SelfLower {
1200
1204
suggest_ampmut (
1201
1205
self . infcx . tcx ,
1202
1206
local_decl. ty ,
@@ -1414,6 +1418,79 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
1414
1418
None => { }
1415
1419
}
1416
1420
}
1421
+
1422
+ /// check if the RHS is an overloaded index expression whose source type
1423
+ /// doesn't implement `IndexMut`. This category contains two sub-categories:
1424
+ /// 1. HashMap or BTreeMap
1425
+ /// 2. Other types
1426
+ /// For the first sub-category, we suggest using `.get_mut()` instead of `&mut`,
1427
+ /// For the second sub-category, we still suggest use `&mut`.
1428
+ /// See issue #143732.
1429
+ ///
1430
+ /// the first element of return value is a boolean indicating
1431
+ /// if we should suggest use `&mut`
1432
+ fn suggest_get_mut_or_ref_mut (
1433
+ & self ,
1434
+ local : Local ,
1435
+ opt_assignment_rhs_span : Option < Span > ,
1436
+ ) -> ( bool , 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 ( adt) = ty. ty_adt_def ( )
1458
+ && ( self . infcx . tcx . is_diagnostic_item ( sym:: HashMap , adt. did ( ) )
1459
+ || self . infcx . tcx . is_diagnostic_item ( sym:: BTreeMap , adt. did ( ) ) )
1460
+ && let Some ( rhs_span) = opt_assignment_rhs_span
1461
+ && let Ok ( rhs_str) =
1462
+ self . infcx . tcx . sess . source_map ( ) . span_to_snippet ( rhs_span)
1463
+ && let Some ( content) = rhs_str. strip_prefix ( '&' )
1464
+ && content. contains ( '[' )
1465
+ && content. contains ( ']' )
1466
+ && let Some ( bracket_start) = content. find ( '[' )
1467
+ && let Some ( bracket_end) = content. rfind ( ']' )
1468
+ && bracket_start < bracket_end
1469
+ {
1470
+ let map_part = & content[ ..bracket_start] ;
1471
+ let key_part = & content[ bracket_start + 1 ..bracket_end] ;
1472
+
1473
+ (
1474
+ false ,
1475
+ Some ( AmpMutSugg {
1476
+ has_sugg : true ,
1477
+ span : rhs_span,
1478
+ suggestion : format ! ( "{}.get_mut({}).unwrap()" , map_part, key_part) ,
1479
+ additional : None ,
1480
+ } ) ,
1481
+ )
1482
+ } else {
1483
+ // Type not implemented `IndexMut`,
1484
+ // and we did not suggest because of HashMap or BTreeMap
1485
+ ( false , None )
1486
+ }
1487
+ } else {
1488
+ // Type Impl IndexMut, we should suggest use `&mut`
1489
+ ( true , None )
1490
+ }
1491
+ } )
1492
+ . unwrap_or ( ( true , None ) )
1493
+ }
1417
1494
}
1418
1495
1419
1496
struct BindingFinder {
0 commit comments