@@ -26,6 +26,7 @@ use rustc_span::hygiene::DesugaringKind;
2626use rustc_span:: symbol:: { kw, sym, Ident } ;
2727use rustc_span:: { BytePos , Span , Symbol } ;
2828use rustc_trait_selection:: infer:: InferCtxtExt ;
29+ use rustc_trait_selection:: traits:: error_reporting:: FindExprBySpan ;
2930use rustc_trait_selection:: traits:: ObligationCtxt ;
3031use std:: iter;
3132
@@ -1304,14 +1305,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
13041305 place : Place < ' tcx > ,
13051306 borrowed_place : Place < ' tcx > ,
13061307 ) {
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 [ ..] )
13091316 {
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+ ) ;
13151398 }
13161399 }
13171400
0 commit comments