@@ -1527,7 +1527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15271527 BorrowKind :: Mut { kind : MutBorrowKind :: Default | MutBorrowKind :: TwoPhaseBorrow } ,
15281528 ) => {
15291529 first_borrow_desc = "mutable " ;
1530- self . cannot_reborrow_already_borrowed (
1530+ let mut err = self . cannot_reborrow_already_borrowed (
15311531 span,
15321532 & desc_place,
15331533 & msg_place,
@@ -1537,7 +1537,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15371537 "mutable" ,
15381538 & msg_borrow,
15391539 None ,
1540- )
1540+ ) ;
1541+ self . suggest_slice_method_if_applicable (
1542+ & mut err,
1543+ place,
1544+ issued_borrow. borrowed_place ,
1545+ span,
1546+ issued_span,
1547+ ) ;
1548+ err
15411549 }
15421550 (
15431551 BorrowKind :: Mut { kind : MutBorrowKind :: Default | MutBorrowKind :: TwoPhaseBorrow } ,
@@ -1555,6 +1563,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15551563 & msg_borrow,
15561564 None ,
15571565 ) ;
1566+ self . suggest_slice_method_if_applicable (
1567+ & mut err,
1568+ place,
1569+ issued_borrow. borrowed_place ,
1570+ span,
1571+ issued_span,
1572+ ) ;
15581573 self . suggest_binding_for_closure_capture_self ( & mut err, & issued_spans) ;
15591574 self . suggest_using_closure_argument_instead_of_capture (
15601575 & mut err,
@@ -1581,6 +1596,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15811596 & mut err,
15821597 place,
15831598 issued_borrow. borrowed_place ,
1599+ span,
1600+ issued_span,
15841601 ) ;
15851602 self . suggest_using_closure_argument_instead_of_capture (
15861603 & mut err,
@@ -2011,40 +2028,47 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20112028 err : & mut Diag < ' _ > ,
20122029 place : Place < ' tcx > ,
20132030 borrowed_place : Place < ' tcx > ,
2031+ span : Span ,
2032+ issued_span : Span ,
20142033 ) {
20152034 let tcx = self . infcx . tcx ;
20162035 let hir = tcx. hir ( ) ;
20172036
2037+ let has_split_at_mut = |ty : Ty < ' tcx > | {
2038+ let ty = ty. peel_refs ( ) ;
2039+ match ty. kind ( ) {
2040+ ty:: Array ( ..) | ty:: Slice ( ..) => true ,
2041+ ty:: Adt ( def, _) if tcx. get_diagnostic_item ( sym:: Vec ) == Some ( def. did ( ) ) => true ,
2042+ _ if ty == tcx. types . str_ => true ,
2043+ _ => false ,
2044+ }
2045+ } ;
20182046 if let ( [ ProjectionElem :: Index ( index1) ] , [ ProjectionElem :: Index ( index2) ] )
20192047 | (
20202048 [ ProjectionElem :: Deref , ProjectionElem :: Index ( index1) ] ,
20212049 [ ProjectionElem :: Deref , ProjectionElem :: Index ( index2) ] ,
20222050 ) = ( & place. projection [ ..] , & borrowed_place. projection [ ..] )
20232051 {
2052+ let decl1 = & self . body . local_decls [ * index1] ;
2053+ let decl2 = & self . body . local_decls [ * index2] ;
2054+
20242055 let mut note_default_suggestion = || {
20252056 err. help (
2026- "consider using `.split_at_mut(position)` or similar method to obtain \
2027- two mutable non-overlapping sub-slices",
2057+ "consider using `.split_at_mut(position)` or similar method to obtain two \
2058+ mutable non-overlapping sub-slices",
20282059 )
2029- . help ( "consider using `.swap(index_1, index_2)` to swap elements at the specified indices" ) ;
2030- } ;
2031-
2032- let Some ( body_id) = tcx. hir_node ( self . mir_hir_id ( ) ) . body_id ( ) else {
2033- note_default_suggestion ( ) ;
2034- return ;
2060+ . help (
2061+ "consider using `.swap(index_1, index_2)` to swap elements at the specified \
2062+ indices",
2063+ ) ;
20352064 } ;
20362065
2037- let mut expr_finder =
2038- FindExprBySpan :: new ( self . body . local_decls [ * index1] . source_info . span , tcx) ;
2039- expr_finder. visit_expr ( hir. body ( body_id) . value ) ;
2040- let Some ( index1) = expr_finder. result else {
2066+ let Some ( index1) = self . find_expr ( decl1. source_info . span ) else {
20412067 note_default_suggestion ( ) ;
20422068 return ;
20432069 } ;
20442070
2045- expr_finder = FindExprBySpan :: new ( self . body . local_decls [ * index2] . source_info . span , tcx) ;
2046- expr_finder. visit_expr ( hir. body ( body_id) . value ) ;
2047- let Some ( index2) = expr_finder. result else {
2071+ let Some ( index2) = self . find_expr ( decl2. source_info . span ) else {
20482072 note_default_suggestion ( ) ;
20492073 return ;
20502074 } ;
@@ -2092,7 +2116,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20922116 None
20932117 }
20942118 } ) else {
2095- note_default_suggestion ( ) ;
2119+ let hir:: Node :: Expr ( parent) = tcx. parent_hir_node ( index1. hir_id ) else { return } ;
2120+ let hir:: ExprKind :: Index ( _, idx1, _) = parent. kind else { return } ;
2121+ let hir:: Node :: Expr ( parent) = tcx. parent_hir_node ( index2. hir_id ) else { return } ;
2122+ let hir:: ExprKind :: Index ( _, idx2, _) = parent. kind else { return } ;
2123+ if !idx1. equivalent_for_indexing ( idx2) {
2124+ err. help ( "use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices" ) ;
2125+ }
20962126 return ;
20972127 } ;
20982128
@@ -2102,7 +2132,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21022132 format ! ( "{obj_str}.swap({index1_str}, {index2_str})" ) ,
21032133 Applicability :: MachineApplicable ,
21042134 ) ;
2135+ return ;
2136+ }
2137+ let place_ty = PlaceRef :: ty ( & place. as_ref ( ) , self . body , tcx) . ty ;
2138+ let borrowed_place_ty = PlaceRef :: ty ( & borrowed_place. as_ref ( ) , self . body , tcx) . ty ;
2139+ if !has_split_at_mut ( place_ty) && !has_split_at_mut ( borrowed_place_ty) {
2140+ // Only mention `split_at_mut` on `Vec`, array and slices.
2141+ return ;
2142+ }
2143+ let Some ( index1) = self . find_expr ( span) else { return } ;
2144+ let hir:: Node :: Expr ( parent) = tcx. parent_hir_node ( index1. hir_id ) else { return } ;
2145+ let hir:: ExprKind :: Index ( _, idx1, _) = parent. kind else { return } ;
2146+ let Some ( index2) = self . find_expr ( issued_span) else { return } ;
2147+ let hir:: Node :: Expr ( parent) = tcx. parent_hir_node ( index2. hir_id ) else { return } ;
2148+ let hir:: ExprKind :: Index ( _, idx2, _) = parent. kind else { return } ;
2149+ if idx1. equivalent_for_indexing ( idx2) {
2150+ // `let a = &mut foo[0]` and `let b = &mut foo[0]`? Don't mention `split_at_mut`
2151+ return ;
21052152 }
2153+ err. help ( "use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices" ) ;
21062154 }
21072155
21082156 /// Suggest using `while let` for call `next` on an iterator in a for loop.
0 commit comments