@@ -26,6 +26,7 @@ use rustc_span::hygiene::DesugaringKind;
26
26
use rustc_span:: symbol:: { kw, sym, Ident } ;
27
27
use rustc_span:: { BytePos , Span , Symbol } ;
28
28
use rustc_trait_selection:: infer:: InferCtxtExt ;
29
+ use rustc_trait_selection:: traits:: error_reporting:: FindExprBySpan ;
29
30
use rustc_trait_selection:: traits:: ObligationCtxt ;
30
31
use std:: iter;
31
32
@@ -1304,14 +1305,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1304
1305
place : Place < ' tcx > ,
1305
1306
borrowed_place : Place < ' tcx > ,
1306
1307
) {
1307
- if let ( [ ProjectionElem :: Index ( _) ] , [ ProjectionElem :: Index ( _) ] ) =
1308
- ( & place. projection [ ..] , & borrowed_place. projection [ ..] )
1308
+ let tcx = self . infcx . tcx ;
1309
+ let hir = tcx. hir ( ) ;
1310
+
1311
+ if let ( [ ProjectionElem :: Index ( index1) ] , [ ProjectionElem :: Index ( index2) ] )
1312
+ | (
1313
+ [ ProjectionElem :: Deref , ProjectionElem :: Index ( index1) ] ,
1314
+ [ ProjectionElem :: Deref , ProjectionElem :: Index ( index2) ] ,
1315
+ ) = ( & place. projection [ ..] , & borrowed_place. projection [ ..] )
1309
1316
{
1310
- err. help (
1311
- "consider using `.split_at_mut(position)` or similar method to obtain \
1312
- two mutable non-overlapping sub-slices",
1313
- )
1314
- . help ( "consider using `.swap(index_1, index_2)` to swap elements at the specified indices" ) ;
1317
+ let mut note_default_suggestion = || {
1318
+ err. help (
1319
+ "consider using `.split_at_mut(position)` or similar method to obtain \
1320
+ two mutable non-overlapping sub-slices",
1321
+ )
1322
+ . help ( "consider using `.swap(index_1, index_2)` to swap elements at the specified indices" ) ;
1323
+ } ;
1324
+
1325
+ let Some ( body_id) = tcx. hir_node ( self . mir_hir_id ( ) ) . body_id ( ) else {
1326
+ note_default_suggestion ( ) ;
1327
+ return ;
1328
+ } ;
1329
+
1330
+ let mut expr_finder =
1331
+ FindExprBySpan :: new ( self . body . local_decls [ * index1] . source_info . span ) ;
1332
+ expr_finder. visit_expr ( hir. body ( body_id) . value ) ;
1333
+ let Some ( index1) = expr_finder. result else {
1334
+ note_default_suggestion ( ) ;
1335
+ return ;
1336
+ } ;
1337
+
1338
+ expr_finder = FindExprBySpan :: new ( self . body . local_decls [ * index2] . source_info . span ) ;
1339
+ expr_finder. visit_expr ( hir. body ( body_id) . value ) ;
1340
+ let Some ( index2) = expr_finder. result else {
1341
+ note_default_suggestion ( ) ;
1342
+ return ;
1343
+ } ;
1344
+
1345
+ let sm = tcx. sess . source_map ( ) ;
1346
+
1347
+ let Ok ( index1_str) = sm. span_to_snippet ( index1. span ) else {
1348
+ note_default_suggestion ( ) ;
1349
+ return ;
1350
+ } ;
1351
+
1352
+ let Ok ( index2_str) = sm. span_to_snippet ( index2. span ) else {
1353
+ note_default_suggestion ( ) ;
1354
+ return ;
1355
+ } ;
1356
+
1357
+ let Some ( object) = hir. parent_id_iter ( index1. hir_id ) . find_map ( |id| {
1358
+ if let hir:: Node :: Expr ( expr) = tcx. hir_node ( id)
1359
+ && let hir:: ExprKind :: Index ( obj, ..) = expr. kind
1360
+ {
1361
+ Some ( obj)
1362
+ } else {
1363
+ None
1364
+ }
1365
+ } ) else {
1366
+ note_default_suggestion ( ) ;
1367
+ return ;
1368
+ } ;
1369
+
1370
+ let Ok ( obj_str) = sm. span_to_snippet ( object. span ) else {
1371
+ note_default_suggestion ( ) ;
1372
+ return ;
1373
+ } ;
1374
+
1375
+ let Some ( swap_call) = hir. parent_id_iter ( object. hir_id ) . find_map ( |id| {
1376
+ if let hir:: Node :: Expr ( call) = tcx. hir_node ( id)
1377
+ && let hir:: ExprKind :: Call ( callee, ..) = call. kind
1378
+ && let hir:: ExprKind :: Path ( qpath) = callee. kind
1379
+ && let hir:: QPath :: Resolved ( None , res) = qpath
1380
+ && let hir:: def:: Res :: Def ( _, did) = res. res
1381
+ && tcx. is_diagnostic_item ( sym:: mem_swap, did)
1382
+ {
1383
+ Some ( call)
1384
+ } else {
1385
+ None
1386
+ }
1387
+ } ) else {
1388
+ note_default_suggestion ( ) ;
1389
+ return ;
1390
+ } ;
1391
+
1392
+ err. span_suggestion (
1393
+ swap_call. span ,
1394
+ "use `.swap()` to swap elements at the specified indices instead" ,
1395
+ format ! ( "{obj_str}.swap({index1_str}, {index2_str})" ) ,
1396
+ Applicability :: MachineApplicable ,
1397
+ ) ;
1315
1398
}
1316
1399
}
1317
1400
0 commit comments