Skip to content

Commit 7af17f7

Browse files
committed
Detect borrow error involving sub-slices and suggest split_at_mut
``` error[E0499]: cannot borrow `foo` as mutable more than once at a time --> $DIR/suggest-split-at-mut.rs:13:18 | LL | let a = &mut foo[..2]; | --- first mutable borrow occurs here LL | let b = &mut foo[2..]; | ^^^ second mutable borrow occurs here LL | a[0] = 5; | ---- first borrow later used here | = help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices ``` Address most of #58792. For follow up work, we should emit a structured suggestion for cases where we can identify the exact `let (a, b) = foo.split_at_mut(2);` call that is needed.
1 parent c2f2db7 commit 7af17f7

File tree

4 files changed

+57
-18
lines changed

4 files changed

+57
-18
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15441544
&mut err,
15451545
place,
15461546
issued_borrow.borrowed_place,
1547+
span,
1548+
issued_span,
15471549
);
15481550
self.suggest_using_closure_argument_instead_of_capture(
15491551
&mut err,
@@ -1974,10 +1976,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
19741976
err: &mut Diag<'_>,
19751977
place: Place<'tcx>,
19761978
borrowed_place: Place<'tcx>,
1979+
span: Span,
1980+
issued_span: Span,
19771981
) {
19781982
let tcx = self.infcx.tcx;
19791983
let hir = tcx.hir();
1980-
19811984
if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
19821985
| (
19831986
[ProjectionElem::Deref, ProjectionElem::Index(index1)],
@@ -1986,28 +1989,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
19861989
{
19871990
let mut note_default_suggestion = || {
19881991
err.help(
1989-
"consider using `.split_at_mut(position)` or similar method to obtain \
1990-
two mutable non-overlapping sub-slices",
1992+
"consider using `.split_at_mut(position)` or similar method to obtain two \
1993+
mutable non-overlapping sub-slices",
19911994
)
1992-
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
1993-
};
1994-
1995-
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else {
1996-
note_default_suggestion();
1997-
return;
1995+
.help(
1996+
"consider using `.swap(index_1, index_2)` to swap elements at the specified \
1997+
indices",
1998+
);
19981999
};
19992000

2000-
let mut expr_finder =
2001-
FindExprBySpan::new(self.body.local_decls[*index1].source_info.span);
2002-
expr_finder.visit_expr(hir.body(body_id).value);
2003-
let Some(index1) = expr_finder.result else {
2001+
let Some(index1) = self.find_expr(self.body.local_decls[*index1].source_info.span)
2002+
else {
20042003
note_default_suggestion();
20052004
return;
20062005
};
20072006

2008-
expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span);
2009-
expr_finder.visit_expr(hir.body(body_id).value);
2010-
let Some(index2) = expr_finder.result else {
2007+
let Some(index2) = self.find_expr(self.body.local_decls[*index2].source_info.span)
2008+
else {
20112009
note_default_suggestion();
20122010
return;
20132011
};
@@ -2065,7 +2063,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20652063
format!("{obj_str}.swap({index1_str}, {index2_str})"),
20662064
Applicability::MachineApplicable,
20672065
);
2066+
return;
20682067
}
2068+
let Some(index1) = self.find_expr(span) else { return };
2069+
let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return };
2070+
let hir::ExprKind::Index(..) = parent.kind else { return };
2071+
let Some(index2) = self.find_expr(issued_span) else { return };
2072+
let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return };
2073+
let hir::ExprKind::Index(..) = parent.kind else { return };
2074+
err.help(
2075+
"use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping \
2076+
sub-slices",
2077+
);
20692078
}
20702079

20712080
/// Suggest using `while let` for call `next` on an iterator in a for loop.

tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ LL | let q = &mut f[&s];
1717
| ^ second mutable borrow occurs here
1818
LL | p.use_mut();
1919
| - first borrow later used here
20+
|
21+
= help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
2022

2123
error[E0499]: cannot borrow `f.foo` as mutable more than once at a time
2224
--> $DIR/borrowck-overloaded-index-autoderef.rs:53:18
@@ -27,6 +29,8 @@ LL | let q = &mut f.foo[&s];
2729
| ^^^^^ second mutable borrow occurs here
2830
LL | p.use_mut();
2931
| - first borrow later used here
32+
|
33+
= help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
3034

3135
error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable
3236
--> $DIR/borrowck-overloaded-index-autoderef.rs:65:18
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1-
fn main() {
1+
fn foo() {
22
let mut foo = [1, 2, 3, 4];
33
let a = &mut foo[2];
44
let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time
55
*a = 5;
66
*b = 6;
77
println!("{:?} {:?}", a, b);
88
}
9+
10+
fn bar() {
11+
let mut foo = [1,2,3,4];
12+
let a = &mut foo[..2];
13+
let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable more than once at a time
14+
a[0] = 5;
15+
b[0] = 6;
16+
println!("{:?} {:?}", a, b);
17+
}
18+
19+
fn main() {
20+
foo();
21+
bar();
22+
}

tests/ui/suggestions/suggest-split-at-mut.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ LL | *a = 5;
1111
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
1212
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
1313

14-
error: aborting due to 1 previous error
14+
error[E0499]: cannot borrow `foo` as mutable more than once at a time
15+
--> $DIR/suggest-split-at-mut.rs:13:18
16+
|
17+
LL | let a = &mut foo[..2];
18+
| --- first mutable borrow occurs here
19+
LL | let b = &mut foo[2..];
20+
| ^^^ second mutable borrow occurs here
21+
LL | a[0] = 5;
22+
| ---- first borrow later used here
23+
|
24+
= help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
25+
26+
error: aborting due to 2 previous errors
1527

1628
For more information about this error, try `rustc --explain E0499`.

0 commit comments

Comments
 (0)