Don't suggest split_at_mut when the multiple borrows have the same index

This commit is contained in:
Esteban Küber 2024-04-24 21:36:10 +00:00
parent 9f9f0aa534
commit ad6ae61246
5 changed files with 60 additions and 5 deletions

View File

@ -2136,10 +2136,14 @@ fn suggest_slice_method_if_applicable(
}
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 hir::ExprKind::Index(_, idx1, _) = 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 };
let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return };
if idx1.equals(idx2) {
// `let a = &mut foo[0]` and `let b = &mut foo[0]`? Don't mention `split_at_mut`
return;
}
err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices");
}

View File

@ -1811,6 +1811,41 @@ pub fn is_approximately_pattern(&self) -> bool {
}
}
/// Whether this and the `other` expression are the same for purposes of an indexing operation.
///
/// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is
/// borrowed multiple times with `i`.
pub fn equals(&self, other: &Expr<'_>) -> bool {
match (self.kind, other.kind) {
(ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node,
(
ExprKind::Path(QPath::LangItem(item1, _)),
ExprKind::Path(QPath::LangItem(item2, _)),
) => item1 == item2,
(
ExprKind::Path(QPath::Resolved(None, path1)),
ExprKind::Path(QPath::Resolved(None, path2)),
) => path1.res == path2.res,
(
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None),
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None),
)
| (
ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None),
ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None),
)
| (
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None),
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None),
) => val1.expr.equals(val2.expr),
(
ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None),
ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None),
) => val1.expr.equals(val2.expr) && val3.expr.equals(val4.expr),
_ => false,
}
}
pub fn method_ident(&self) -> Option<Ident> {
match self.kind {
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),

View File

@ -9,8 +9,6 @@ LL | p[0] = 5;
LL |
LL | println!("{}", *q);
| -- immutable borrow later used here
|
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-assign-comp-idx.rs:27:9

View File

@ -48,6 +48,14 @@ fn bat() {
println!("{:?} {:?}", a, b);
}
fn ang() {
let mut foo = [1,2,3,4];
let a = &mut foo[0..];
let b = &foo[0..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
a[0] = 5;
println!("{:?} {:?}", a, b);
}
fn main() {
foo();
bar();

View File

@ -75,7 +75,17 @@ LL | *a = 5;
= 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
error: aborting due to 6 previous errors
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
--> $DIR/suggest-split-at-mut.rs:54:14
|
LL | let a = &mut foo[0..];
| --- mutable borrow occurs here
LL | let b = &foo[0..];
| ^^^ immutable borrow occurs here
LL | a[0] = 5;
| ---- mutable borrow later used here
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0499, E0502.
For more information about an error, try `rustc --explain E0499`.