Skip to content

Commit ad6ae61

Browse files
committed
Don't suggest split_at_mut when the multiple borrows have the same index
1 parent 9f9f0aa commit ad6ae61

File tree

5 files changed

+60
-5
lines changed

5 files changed

+60
-5
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2136,10 +2136,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21362136
}
21372137
let Some(index1) = self.find_expr(span) else { return };
21382138
let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return };
2139-
let hir::ExprKind::Index(..) = parent.kind else { return };
2139+
let hir::ExprKind::Index(_, idx1, _) = parent.kind else { return };
21402140
let Some(index2) = self.find_expr(issued_span) else { return };
21412141
let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return };
2142-
let hir::ExprKind::Index(..) = parent.kind else { return };
2142+
let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return };
2143+
if idx1.equals(idx2) {
2144+
// `let a = &mut foo[0]` and `let b = &mut foo[0]`? Don't mention `split_at_mut`
2145+
return;
2146+
}
21432147
err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices");
21442148
}
21452149

compiler/rustc_hir/src/hir.rs

+35
Original file line numberDiff line numberDiff line change
@@ -1811,6 +1811,41 @@ impl Expr<'_> {
18111811
}
18121812
}
18131813

1814+
/// Whether this and the `other` expression are the same for purposes of an indexing operation.
1815+
///
1816+
/// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is
1817+
/// borrowed multiple times with `i`.
1818+
pub fn equals(&self, other: &Expr<'_>) -> bool {
1819+
match (self.kind, other.kind) {
1820+
(ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node,
1821+
(
1822+
ExprKind::Path(QPath::LangItem(item1, _)),
1823+
ExprKind::Path(QPath::LangItem(item2, _)),
1824+
) => item1 == item2,
1825+
(
1826+
ExprKind::Path(QPath::Resolved(None, path1)),
1827+
ExprKind::Path(QPath::Resolved(None, path2)),
1828+
) => path1.res == path2.res,
1829+
(
1830+
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None),
1831+
ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None),
1832+
)
1833+
| (
1834+
ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None),
1835+
ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None),
1836+
)
1837+
| (
1838+
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None),
1839+
ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None),
1840+
) => val1.expr.equals(val2.expr),
1841+
(
1842+
ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None),
1843+
ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None),
1844+
) => val1.expr.equals(val2.expr) && val3.expr.equals(val4.expr),
1845+
_ => false,
1846+
}
1847+
}
1848+
18141849
pub fn method_ident(&self) -> Option<Ident> {
18151850
match self.kind {
18161851
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),

tests/ui/borrowck/borrowck-assign-comp-idx.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ LL | p[0] = 5;
99
LL |
1010
LL | println!("{}", *q);
1111
| -- immutable borrow later used here
12-
|
13-
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
1412

1513
error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
1614
--> $DIR/borrowck-assign-comp-idx.rs:27:9

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

+8
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ fn bat() {
4848
println!("{:?} {:?}", a, b);
4949
}
5050

51+
fn ang() {
52+
let mut foo = [1,2,3,4];
53+
let a = &mut foo[0..];
54+
let b = &foo[0..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
55+
a[0] = 5;
56+
println!("{:?} {:?}", a, b);
57+
}
58+
5159
fn main() {
5260
foo();
5361
bar();

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,17 @@ LL | *a = 5;
7575
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
7676
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
7777

78-
error: aborting due to 6 previous errors
78+
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
79+
--> $DIR/suggest-split-at-mut.rs:54:14
80+
|
81+
LL | let a = &mut foo[0..];
82+
| --- mutable borrow occurs here
83+
LL | let b = &foo[0..];
84+
| ^^^ immutable borrow occurs here
85+
LL | a[0] = 5;
86+
| ---- mutable borrow later used here
87+
88+
error: aborting due to 7 previous errors
7989

8090
Some errors have detailed explanations: E0499, E0502.
8191
For more information about an error, try `rustc --explain E0499`.

0 commit comments

Comments
 (0)