@@ -1527,7 +1527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1527
1527
BorrowKind :: Mut { kind : MutBorrowKind :: Default | MutBorrowKind :: TwoPhaseBorrow } ,
1528
1528
) => {
1529
1529
first_borrow_desc = "mutable " ;
1530
- self . cannot_reborrow_already_borrowed (
1530
+ let mut err = self . cannot_reborrow_already_borrowed (
1531
1531
span,
1532
1532
& desc_place,
1533
1533
& msg_place,
@@ -1537,7 +1537,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1537
1537
"mutable" ,
1538
1538
& msg_borrow,
1539
1539
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
1541
1549
}
1542
1550
(
1543
1551
BorrowKind :: Mut { kind : MutBorrowKind :: Default | MutBorrowKind :: TwoPhaseBorrow } ,
@@ -1555,6 +1563,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1555
1563
& msg_borrow,
1556
1564
None ,
1557
1565
) ;
1566
+ self . suggest_slice_method_if_applicable (
1567
+ & mut err,
1568
+ place,
1569
+ issued_borrow. borrowed_place ,
1570
+ span,
1571
+ issued_span,
1572
+ ) ;
1558
1573
self . suggest_binding_for_closure_capture_self ( & mut err, & issued_spans) ;
1559
1574
self . suggest_using_closure_argument_instead_of_capture (
1560
1575
& mut err,
@@ -1581,6 +1596,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1581
1596
& mut err,
1582
1597
place,
1583
1598
issued_borrow. borrowed_place ,
1599
+ span,
1600
+ issued_span,
1584
1601
) ;
1585
1602
self . suggest_using_closure_argument_instead_of_capture (
1586
1603
& mut err,
@@ -2011,40 +2028,47 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2011
2028
err : & mut Diag < ' _ > ,
2012
2029
place : Place < ' tcx > ,
2013
2030
borrowed_place : Place < ' tcx > ,
2031
+ span : Span ,
2032
+ issued_span : Span ,
2014
2033
) {
2015
2034
let tcx = self . infcx . tcx ;
2016
2035
let hir = tcx. hir ( ) ;
2017
2036
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
+ } ;
2018
2046
if let ( [ ProjectionElem :: Index ( index1) ] , [ ProjectionElem :: Index ( index2) ] )
2019
2047
| (
2020
2048
[ ProjectionElem :: Deref , ProjectionElem :: Index ( index1) ] ,
2021
2049
[ ProjectionElem :: Deref , ProjectionElem :: Index ( index2) ] ,
2022
2050
) = ( & place. projection [ ..] , & borrowed_place. projection [ ..] )
2023
2051
{
2052
+ let decl1 = & self . body . local_decls [ * index1] ;
2053
+ let decl2 = & self . body . local_decls [ * index2] ;
2054
+
2024
2055
let mut note_default_suggestion = || {
2025
2056
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",
2028
2059
)
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
+ ) ;
2035
2064
} ;
2036
2065
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 {
2041
2067
note_default_suggestion ( ) ;
2042
2068
return ;
2043
2069
} ;
2044
2070
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 {
2048
2072
note_default_suggestion ( ) ;
2049
2073
return ;
2050
2074
} ;
@@ -2092,7 +2116,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2092
2116
None
2093
2117
}
2094
2118
} ) 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
+ }
2096
2126
return ;
2097
2127
} ;
2098
2128
@@ -2102,7 +2132,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2102
2132
format ! ( "{obj_str}.swap({index1_str}, {index2_str})" ) ,
2103
2133
Applicability :: MachineApplicable ,
2104
2134
) ;
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 ;
2105
2152
}
2153
+ err. help ( "use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices" ) ;
2106
2154
}
2107
2155
2108
2156
/// Suggest using `while let` for call `next` on an iterator in a for loop.
0 commit comments