Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 06d02e0

Browse files
committed
Auto merge of rust-lang#14893 - HKalbasi:dev, r=HKalbasi
Fix `need-mut` false positive in closure capture of match scrutinee Fix `need-mut` false positive on self.
2 parents fcd3a6b + 780349b commit 06d02e0

File tree

4 files changed

+72
-14
lines changed

4 files changed

+72
-14
lines changed

crates/hir-def/src/body.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,8 @@ impl Body {
227227
});
228228
}
229229

230-
pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) {
230+
pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) {
231231
let pat = &self[pat_id];
232-
f(pat_id);
233232
match pat {
234233
Pat::Range { .. }
235234
| Pat::Lit(..)
@@ -239,23 +238,28 @@ impl Body {
239238
| Pat::Missing => {}
240239
&Pat::Bind { subpat, .. } => {
241240
if let Some(subpat) = subpat {
242-
self.walk_pats(subpat, f);
241+
f(subpat);
243242
}
244243
}
245244
Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
246-
args.iter().copied().for_each(|p| self.walk_pats(p, f));
245+
args.iter().copied().for_each(|p| f(p));
247246
}
248-
Pat::Ref { pat, .. } => self.walk_pats(*pat, f),
247+
Pat::Ref { pat, .. } => f(*pat),
249248
Pat::Slice { prefix, slice, suffix } => {
250249
let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
251-
total_iter.copied().for_each(|p| self.walk_pats(p, f));
250+
total_iter.copied().for_each(|p| f(p));
252251
}
253252
Pat::Record { args, .. } => {
254-
args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f));
253+
args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat));
255254
}
256-
Pat::Box { inner } => self.walk_pats(*inner, f),
255+
Pat::Box { inner } => f(*inner),
257256
}
258257
}
258+
259+
pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) {
260+
f(pat_id);
261+
self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f));
262+
}
259263
}
260264

261265
impl Default for Body {

crates/hir-ty/src/infer/closure.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,21 @@ impl InferenceContext<'_> {
643643
}
644644
None => *result = Some(ck),
645645
};
646-
self.body.walk_pats(pat, &mut |p| match &self.body[p] {
646+
647+
self.walk_pat_inner(
648+
pat,
649+
&mut update_result,
650+
BorrowKind::Mut { allow_two_phase_borrow: false },
651+
);
652+
}
653+
654+
fn walk_pat_inner(
655+
&mut self,
656+
p: PatId,
657+
update_result: &mut impl FnMut(CaptureKind),
658+
mut for_mut: BorrowKind,
659+
) {
660+
match &self.body[p] {
647661
Pat::Ref { .. }
648662
| Pat::Box { .. }
649663
| Pat::Missing
@@ -678,13 +692,15 @@ impl InferenceContext<'_> {
678692
}
679693
}
680694
crate::BindingMode::Ref(r) => match r {
681-
Mutability::Mut => update_result(CaptureKind::ByRef(BorrowKind::Mut {
682-
allow_two_phase_borrow: false,
683-
})),
695+
Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)),
684696
Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)),
685697
},
686698
},
687-
});
699+
}
700+
if self.result.pat_adjustments.get(&p).map_or(false, |x| !x.is_empty()) {
701+
for_mut = BorrowKind::Unique;
702+
}
703+
self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut));
688704
}
689705

690706
fn expr_ty(&self, expr: ExprId) -> Ty {

crates/hir-ty/src/layout/tests/closure.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ fn match_pattern() {
201201
]
202202
|x: i64| {
203203
match y {
204-
X(_a, _b, _c) => x,
204+
X(_a, _, _c) => x,
205205
}
206206
}
207207
}
@@ -217,6 +217,18 @@ fn match_pattern() {
217217
}
218218
}
219219
}
220+
size_and_align_expr! {
221+
minicore: copy;
222+
stmts: [
223+
struct X(i64, i32, (u8, i128));
224+
let y: X = X(2, 5, (7, 3));
225+
]
226+
|x: i64| {
227+
match y {
228+
ref _y => x,
229+
}
230+
}
231+
}
220232
}
221233

222234
#[test]

crates/ide-diagnostics/src/handlers/mutability_errors.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,32 @@ fn main() {
352352
);
353353
}
354354

355+
#[test]
356+
fn match_closure_capture() {
357+
check_diagnostics(
358+
r#"
359+
//- minicore: option
360+
fn main() {
361+
let mut v = &mut Some(2);
362+
//^^^^^ 💡 weak: variable does not need to be mutable
363+
let _ = || match v {
364+
Some(k) => {
365+
*k = 5;
366+
}
367+
None => {}
368+
};
369+
let v = &mut Some(2);
370+
let _ = || match v {
371+
//^ 💡 error: cannot mutate immutable variable `v`
372+
ref mut k => {
373+
*k = &mut Some(5);
374+
}
375+
};
376+
}
377+
"#,
378+
);
379+
}
380+
355381
#[test]
356382
fn match_bindings() {
357383
check_diagnostics(

0 commit comments

Comments
 (0)