Skip to content

Commit

Permalink
Don't suggest split_at_mut when the multiple borrows have the same …
Browse files Browse the repository at this point in the history
…index
  • Loading branch information
estebank committed Apr 24, 2024
1 parent 0bc642e commit 627089f
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 5 deletions.
8 changes: 6 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2099,10 +2099,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
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");
}

Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,41 @@ impl Expr<'_> {
}
}

/// 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),
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/borrowck/borrowck-assign-comp-idx.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/suggestions/suggest-split-at-mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 11 additions & 1 deletion tests/ui/suggestions/suggest-split-at-mut.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

0 comments on commit 627089f

Please sign in to comment.