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