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.
This commit is contained in:
parent
6a9758d4f3
commit
386236f289
4 changed files with 57 additions and 18 deletions
|
@ -1581,6 +1581,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
&mut err,
|
&mut err,
|
||||||
place,
|
place,
|
||||||
issued_borrow.borrowed_place,
|
issued_borrow.borrowed_place,
|
||||||
|
span,
|
||||||
|
issued_span,
|
||||||
);
|
);
|
||||||
self.suggest_using_closure_argument_instead_of_capture(
|
self.suggest_using_closure_argument_instead_of_capture(
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -2011,10 +2013,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
place: Place<'tcx>,
|
place: Place<'tcx>,
|
||||||
borrowed_place: Place<'tcx>,
|
borrowed_place: Place<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
issued_span: Span,
|
||||||
) {
|
) {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
|
|
||||||
if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
|
if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
|
||||||
| (
|
| (
|
||||||
[ProjectionElem::Deref, ProjectionElem::Index(index1)],
|
[ProjectionElem::Deref, ProjectionElem::Index(index1)],
|
||||||
|
@ -2023,28 +2026,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
{
|
{
|
||||||
let mut note_default_suggestion = || {
|
let mut note_default_suggestion = || {
|
||||||
err.help(
|
err.help(
|
||||||
"consider using `.split_at_mut(position)` or similar method to obtain \
|
"consider using `.split_at_mut(position)` or similar method to obtain two \
|
||||||
two mutable non-overlapping sub-slices",
|
mutable non-overlapping sub-slices",
|
||||||
)
|
)
|
||||||
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
|
.help(
|
||||||
|
"consider using `.swap(index_1, index_2)` to swap elements at the specified \
|
||||||
|
indices",
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else {
|
let Some(index1) = self.find_expr(self.body.local_decls[*index1].source_info.span)
|
||||||
|
else {
|
||||||
note_default_suggestion();
|
note_default_suggestion();
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut expr_finder =
|
let Some(index2) = self.find_expr(self.body.local_decls[*index2].source_info.span)
|
||||||
FindExprBySpan::new(self.body.local_decls[*index1].source_info.span, tcx);
|
else {
|
||||||
expr_finder.visit_expr(hir.body(body_id).value);
|
|
||||||
let Some(index1) = expr_finder.result else {
|
|
||||||
note_default_suggestion();
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span, tcx);
|
|
||||||
expr_finder.visit_expr(hir.body(body_id).value);
|
|
||||||
let Some(index2) = expr_finder.result else {
|
|
||||||
note_default_suggestion();
|
note_default_suggestion();
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -2102,7 +2100,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
format!("{obj_str}.swap({index1_str}, {index2_str})"),
|
format!("{obj_str}.swap({index1_str}, {index2_str})"),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
let Some(index1) = self.find_expr(span) else { return };
|
||||||
|
let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return };
|
||||||
|
let hir::ExprKind::Index(..) = parent.kind else { return };
|
||||||
|
let Some(index2) = self.find_expr(issued_span) else { return };
|
||||||
|
let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return };
|
||||||
|
let hir::ExprKind::Index(..) = parent.kind else { return };
|
||||||
|
err.help(
|
||||||
|
"use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping \
|
||||||
|
sub-slices",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Suggest using `while let` for call `next` on an iterator in a for loop.
|
/// Suggest using `while let` for call `next` on an iterator in a for loop.
|
||||||
|
|
|
@ -17,6 +17,8 @@ LL | let q = &mut f[&s];
|
||||||
| ^ second mutable borrow occurs here
|
| ^ second mutable borrow occurs here
|
||||||
LL | p.use_mut();
|
LL | p.use_mut();
|
||||||
| - first borrow later used here
|
| - first borrow later used here
|
||||||
|
|
|
||||||
|
= help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
|
||||||
|
|
||||||
error[E0499]: cannot borrow `f.foo` as mutable more than once at a time
|
error[E0499]: cannot borrow `f.foo` as mutable more than once at a time
|
||||||
--> $DIR/borrowck-overloaded-index-autoderef.rs:53:18
|
--> $DIR/borrowck-overloaded-index-autoderef.rs:53:18
|
||||||
|
@ -27,6 +29,8 @@ LL | let q = &mut f.foo[&s];
|
||||||
| ^^^^^ second mutable borrow occurs here
|
| ^^^^^ second mutable borrow occurs here
|
||||||
LL | p.use_mut();
|
LL | p.use_mut();
|
||||||
| - first borrow later used here
|
| - first borrow later used here
|
||||||
|
|
|
||||||
|
= help: use `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
|
||||||
|
|
||||||
error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable
|
error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable
|
||||||
--> $DIR/borrowck-overloaded-index-autoderef.rs:65:18
|
--> $DIR/borrowck-overloaded-index-autoderef.rs:65:18
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fn main() {
|
fn foo() {
|
||||||
let mut foo = [1, 2, 3, 4];
|
let mut foo = [1, 2, 3, 4];
|
||||||
let a = &mut foo[2];
|
let a = &mut foo[2];
|
||||||
let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time
|
let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time
|
||||||
|
@ -6,3 +6,17 @@ fn main() {
|
||||||
*b = 6;
|
*b = 6;
|
||||||
println!("{:?} {:?}", a, b);
|
println!("{:?} {:?}", a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
let mut foo = [1,2,3,4];
|
||||||
|
let a = &mut foo[..2];
|
||||||
|
let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable more than once at a time
|
||||||
|
a[0] = 5;
|
||||||
|
b[0] = 6;
|
||||||
|
println!("{:?} {:?}", a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,18 @@ LL | *a = 5;
|
||||||
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
|
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
|
||||||
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
|
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
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
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0499`.
|
For more information about this error, try `rustc --explain E0499`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue