mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
fix need-mut
false positive in closure capture of match scrutinee
This commit is contained in:
parent
7ef185d65e
commit
780349bdaf
4 changed files with 72 additions and 14 deletions
|
@ -227,9 +227,8 @@ impl Body {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) {
|
||||
pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) {
|
||||
let pat = &self[pat_id];
|
||||
f(pat_id);
|
||||
match pat {
|
||||
Pat::Range { .. }
|
||||
| Pat::Lit(..)
|
||||
|
@ -239,23 +238,28 @@ impl Body {
|
|||
| Pat::Missing => {}
|
||||
&Pat::Bind { subpat, .. } => {
|
||||
if let Some(subpat) = subpat {
|
||||
self.walk_pats(subpat, f);
|
||||
f(subpat);
|
||||
}
|
||||
}
|
||||
Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
|
||||
args.iter().copied().for_each(|p| self.walk_pats(p, f));
|
||||
args.iter().copied().for_each(|p| f(p));
|
||||
}
|
||||
Pat::Ref { pat, .. } => self.walk_pats(*pat, f),
|
||||
Pat::Ref { pat, .. } => f(*pat),
|
||||
Pat::Slice { prefix, slice, suffix } => {
|
||||
let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
|
||||
total_iter.copied().for_each(|p| self.walk_pats(p, f));
|
||||
total_iter.copied().for_each(|p| f(p));
|
||||
}
|
||||
Pat::Record { args, .. } => {
|
||||
args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f));
|
||||
args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat));
|
||||
}
|
||||
Pat::Box { inner } => self.walk_pats(*inner, f),
|
||||
Pat::Box { inner } => f(*inner),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) {
|
||||
f(pat_id);
|
||||
self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f));
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Body {
|
||||
|
|
|
@ -643,7 +643,21 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
None => *result = Some(ck),
|
||||
};
|
||||
self.body.walk_pats(pat, &mut |p| match &self.body[p] {
|
||||
|
||||
self.walk_pat_inner(
|
||||
pat,
|
||||
&mut update_result,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
);
|
||||
}
|
||||
|
||||
fn walk_pat_inner(
|
||||
&mut self,
|
||||
p: PatId,
|
||||
update_result: &mut impl FnMut(CaptureKind),
|
||||
mut for_mut: BorrowKind,
|
||||
) {
|
||||
match &self.body[p] {
|
||||
Pat::Ref { .. }
|
||||
| Pat::Box { .. }
|
||||
| Pat::Missing
|
||||
|
@ -678,13 +692,15 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
}
|
||||
crate::BindingMode::Ref(r) => match r {
|
||||
Mutability::Mut => update_result(CaptureKind::ByRef(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
})),
|
||||
Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)),
|
||||
Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
if self.result.pat_adjustments.get(&p).map_or(false, |x| !x.is_empty()) {
|
||||
for_mut = BorrowKind::Unique;
|
||||
}
|
||||
self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut));
|
||||
}
|
||||
|
||||
fn expr_ty(&self, expr: ExprId) -> Ty {
|
||||
|
|
|
@ -201,7 +201,7 @@ fn match_pattern() {
|
|||
]
|
||||
|x: i64| {
|
||||
match y {
|
||||
X(_a, _b, _c) => x,
|
||||
X(_a, _, _c) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +217,18 @@ fn match_pattern() {
|
|||
}
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
]
|
||||
|x: i64| {
|
||||
match y {
|
||||
ref _y => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -352,6 +352,32 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_closure_capture() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- minicore: option
|
||||
fn main() {
|
||||
let mut v = &mut Some(2);
|
||||
//^^^^^ 💡 weak: variable does not need to be mutable
|
||||
let _ = || match v {
|
||||
Some(k) => {
|
||||
*k = 5;
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
let v = &mut Some(2);
|
||||
let _ = || match v {
|
||||
//^ 💡 error: cannot mutate immutable variable `v`
|
||||
ref mut k => {
|
||||
*k = &mut Some(5);
|
||||
}
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_bindings() {
|
||||
check_diagnostics(
|
||||
|
|
Loading…
Reference in a new issue