diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9216f9e4971..84f9ebf18a8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -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"); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2268905430a..1e66d42c227 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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 { match self.kind { ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), diff --git a/tests/ui/borrowck/borrowck-assign-comp-idx.stderr b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr index 914c79ecee5..b80174ae687 100644 --- a/tests/ui/borrowck/borrowck-assign-comp-idx.stderr +++ b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr @@ -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 diff --git a/tests/ui/suggestions/suggest-split-at-mut.rs b/tests/ui/suggestions/suggest-split-at-mut.rs index 93f9120048b..61704abbd36 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.rs +++ b/tests/ui/suggestions/suggest-split-at-mut.rs @@ -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(); diff --git a/tests/ui/suggestions/suggest-split-at-mut.stderr b/tests/ui/suggestions/suggest-split-at-mut.stderr index 68b1ddc45c7..c1d93367ccb 100644 --- a/tests/ui/suggestions/suggest-split-at-mut.stderr +++ b/tests/ui/suggestions/suggest-split-at-mut.stderr @@ -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`.