mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +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];
|
let pat = &self[pat_id];
|
||||||
f(pat_id);
|
|
||||||
match pat {
|
match pat {
|
||||||
Pat::Range { .. }
|
Pat::Range { .. }
|
||||||
| Pat::Lit(..)
|
| Pat::Lit(..)
|
||||||
|
@ -239,23 +238,28 @@ impl Body {
|
||||||
| Pat::Missing => {}
|
| Pat::Missing => {}
|
||||||
&Pat::Bind { subpat, .. } => {
|
&Pat::Bind { subpat, .. } => {
|
||||||
if let Some(subpat) = subpat {
|
if let Some(subpat) = subpat {
|
||||||
self.walk_pats(subpat, f);
|
f(subpat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
|
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 } => {
|
Pat::Slice { prefix, slice, suffix } => {
|
||||||
let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
|
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, .. } => {
|
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 {
|
impl Default for Body {
|
||||||
|
|
|
@ -643,7 +643,21 @@ impl InferenceContext<'_> {
|
||||||
}
|
}
|
||||||
None => *result = Some(ck),
|
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::Ref { .. }
|
||||||
| Pat::Box { .. }
|
| Pat::Box { .. }
|
||||||
| Pat::Missing
|
| Pat::Missing
|
||||||
|
@ -678,13 +692,15 @@ impl InferenceContext<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::BindingMode::Ref(r) => match r {
|
crate::BindingMode::Ref(r) => match r {
|
||||||
Mutability::Mut => update_result(CaptureKind::ByRef(BorrowKind::Mut {
|
Mutability::Mut => update_result(CaptureKind::ByRef(for_mut)),
|
||||||
allow_two_phase_borrow: false,
|
|
||||||
})),
|
|
||||||
Mutability::Not => update_result(CaptureKind::ByRef(BorrowKind::Shared)),
|
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 {
|
fn expr_ty(&self, expr: ExprId) -> Ty {
|
||||||
|
|
|
@ -201,7 +201,7 @@ fn match_pattern() {
|
||||||
]
|
]
|
||||||
|x: i64| {
|
|x: i64| {
|
||||||
match y {
|
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]
|
#[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]
|
#[test]
|
||||||
fn match_bindings() {
|
fn match_bindings() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
|
|
Loading…
Reference in a new issue