Skip to content

Commit c198569

Browse files
committed
Always do all the pattern checks
1 parent b60f08a commit c198569

File tree

3 files changed

+82
-64
lines changed

3 files changed

+82
-64
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn create_e0004(
5858
struct_span_err!(sess, sp, E0004, "{}", &error_message)
5959
}
6060

61-
#[derive(PartialEq)]
61+
#[derive(Copy, Clone, PartialEq)]
6262
enum RefutableFlag {
6363
Irrefutable,
6464
Refutable,
@@ -197,32 +197,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
197197
self.let_source = old_let_source;
198198
}
199199

200-
fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
200+
fn with_lint_level<T>(
201+
&mut self,
202+
new_lint_level: LintLevel,
203+
f: impl FnOnce(&mut Self) -> T,
204+
) -> T {
201205
if let LintLevel::Explicit(hir_id) = new_lint_level {
202206
let old_lint_level = self.lint_level;
203207
self.lint_level = hir_id;
204-
f(self);
208+
let ret = f(self);
205209
self.lint_level = old_lint_level;
210+
ret
206211
} else {
207-
f(self);
212+
f(self)
208213
}
209214
}
210215

211-
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
212-
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
213-
check_for_bindings_named_same_as_variants(self, pat, rf);
214-
}
215-
216216
fn lower_pattern(
217217
&mut self,
218218
cx: &MatchCheckCtxt<'p, 'tcx>,
219-
pattern: &Pat<'tcx>,
219+
pat: &Pat<'tcx>,
220220
) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> {
221-
if let Err(err) = pattern.pat_error_reported() {
221+
if let Err(err) = pat.pat_error_reported() {
222222
self.error = Err(err);
223223
Err(err)
224224
} else {
225-
Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pattern)))
225+
// Check the pattern for some things unrelated to exhaustiveness.
226+
let refutable = if cx.refutable { Refutable } else { Irrefutable };
227+
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
228+
pat.walk_always(|pat| check_for_bindings_named_same_as_variants(self, pat, refutable));
229+
Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat)))
226230
}
227231
}
228232

@@ -241,7 +245,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
241245
if let LetSource::None = source {
242246
return;
243247
}
244-
self.check_patterns(pat, Refutable);
245248
let mut cx = self.new_cx(self.lint_level, true);
246249
let Ok(tpat) = self.lower_pattern(&cx, pat) else { return };
247250
self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span);
@@ -258,18 +261,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
258261

259262
let mut tarms = Vec::with_capacity(arms.len());
260263
for &arm in arms {
261-
// Check the arm for some things unrelated to exhaustiveness.
262264
let arm = &self.thir.arms[arm];
263-
self.with_lint_level(arm.lint_level, |this| {
264-
this.check_patterns(&arm.pattern, Refutable);
265+
let got_error = self.with_lint_level(arm.lint_level, |this| {
266+
let Ok(pat) = this.lower_pattern(&mut cx, &arm.pattern) else {
267+
return true;
268+
};
269+
let arm = MatchArm { pat, hir_id: this.lint_level, has_guard: arm.guard.is_some() };
270+
tarms.push(arm);
271+
false
265272
});
266-
let hir_id = match arm.lint_level {
267-
LintLevel::Explicit(hir_id) => hir_id,
268-
LintLevel::Inherited => self.lint_level,
269-
};
270-
let Ok(pat) = self.lower_pattern(&mut cx, &arm.pattern) else { return };
271-
let arm = MatchArm { pat, hir_id, has_guard: arm.guard.is_some() };
272-
tarms.push(arm);
273+
if got_error {
274+
return;
275+
}
273276
}
274277

275278
let scrut = &self.thir[scrut];
@@ -458,7 +461,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
458461
let witnesses = report.non_exhaustiveness_witnesses;
459462
if witnesses.is_empty() {
460463
// The pattern is irrefutable.
461-
self.check_patterns(pat, Irrefutable);
462464
return;
463465
}
464466

@@ -659,43 +661,41 @@ fn check_for_bindings_named_same_as_variants(
659661
pat: &Pat<'_>,
660662
rf: RefutableFlag,
661663
) {
662-
pat.walk_always(|p| {
663-
if let PatKind::Binding {
664-
name,
665-
mode: BindingMode::ByValue,
666-
mutability: Mutability::Not,
667-
subpattern: None,
668-
ty,
669-
..
670-
} = p.kind
671-
&& let ty::Adt(edef, _) = ty.peel_refs().kind()
672-
&& edef.is_enum()
673-
&& edef
674-
.variants()
675-
.iter()
676-
.any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const))
677-
{
678-
let variant_count = edef.variants().len();
679-
let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did()));
680-
cx.tcx.emit_spanned_lint(
681-
BINDINGS_WITH_VARIANT_NAME,
682-
cx.lint_level,
683-
p.span,
684-
BindingsWithVariantName {
685-
// If this is an irrefutable pattern, and there's > 1 variant,
686-
// then we can't actually match on this. Applying the below
687-
// suggestion would produce code that breaks on `check_irrefutable`.
688-
suggestion: if rf == Refutable || variant_count == 1 {
689-
Some(p.span)
690-
} else {
691-
None
692-
},
693-
ty_path,
694-
name,
664+
if let PatKind::Binding {
665+
name,
666+
mode: BindingMode::ByValue,
667+
mutability: Mutability::Not,
668+
subpattern: None,
669+
ty,
670+
..
671+
} = pat.kind
672+
&& let ty::Adt(edef, _) = ty.peel_refs().kind()
673+
&& edef.is_enum()
674+
&& edef
675+
.variants()
676+
.iter()
677+
.any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const))
678+
{
679+
let variant_count = edef.variants().len();
680+
let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did()));
681+
cx.tcx.emit_spanned_lint(
682+
BINDINGS_WITH_VARIANT_NAME,
683+
cx.lint_level,
684+
pat.span,
685+
BindingsWithVariantName {
686+
// If this is an irrefutable pattern, and there's > 1 variant,
687+
// then we can't actually match on this. Applying the below
688+
// suggestion would produce code that breaks on `check_irrefutable`.
689+
suggestion: if rf == Refutable || variant_count == 1 {
690+
Some(pat.span)
691+
} else {
692+
None
695693
},
696-
)
697-
}
698-
});
694+
ty_path,
695+
name,
696+
},
697+
)
698+
}
699699
}
700700

701701
fn irrefutable_let_patterns(

tests/ui/pattern/usefulness/conflicting_bindings.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ fn main() {
99
if let Some(ref mut y @ ref mut z) = x {}
1010
//~^ ERROR: mutable more than once
1111
if let Some(ref mut y @ ref mut z) = x && true {}
12+
//~^ ERROR: mutable more than once
1213
while let Some(ref mut y @ ref mut z) = x {}
1314
//~^ ERROR: mutable more than once
1415
while let Some(ref mut y @ ref mut z) = x && true {}
16+
//~^ ERROR: mutable more than once
1517
match x {
1618
ref mut y @ ref mut z => {} //~ ERROR: mutable more than once
1719
}

tests/ui/pattern/usefulness/conflicting_bindings.stderr

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,44 @@ LL | if let Some(ref mut y @ ref mut z) = x {}
2323
| value is mutably borrowed by `y` here
2424

2525
error: cannot borrow value as mutable more than once at a time
26-
--> $DIR/conflicting_bindings.rs:12:20
26+
--> $DIR/conflicting_bindings.rs:11:17
27+
|
28+
LL | if let Some(ref mut y @ ref mut z) = x && true {}
29+
| ^^^^^^^^^ --------- value is mutably borrowed by `z` here
30+
| |
31+
| value is mutably borrowed by `y` here
32+
33+
error: cannot borrow value as mutable more than once at a time
34+
--> $DIR/conflicting_bindings.rs:13:20
2735
|
2836
LL | while let Some(ref mut y @ ref mut z) = x {}
2937
| ^^^^^^^^^ --------- value is mutably borrowed by `z` here
3038
| |
3139
| value is mutably borrowed by `y` here
3240

3341
error: cannot borrow value as mutable more than once at a time
34-
--> $DIR/conflicting_bindings.rs:16:9
42+
--> $DIR/conflicting_bindings.rs:15:20
43+
|
44+
LL | while let Some(ref mut y @ ref mut z) = x && true {}
45+
| ^^^^^^^^^ --------- value is mutably borrowed by `z` here
46+
| |
47+
| value is mutably borrowed by `y` here
48+
49+
error: cannot borrow value as mutable more than once at a time
50+
--> $DIR/conflicting_bindings.rs:18:9
3551
|
3652
LL | ref mut y @ ref mut z => {}
3753
| ^^^^^^^^^ --------- value is mutably borrowed by `z` here
3854
| |
3955
| value is mutably borrowed by `y` here
4056

4157
error: cannot borrow value as mutable more than once at a time
42-
--> $DIR/conflicting_bindings.rs:19:24
58+
--> $DIR/conflicting_bindings.rs:21:24
4359
|
4460
LL | () if let Some(ref mut y @ ref mut z) = x => {}
4561
| ^^^^^^^^^ --------- value is mutably borrowed by `z` here
4662
| |
4763
| value is mutably borrowed by `y` here
4864

49-
error: aborting due to 6 previous errors
65+
error: aborting due to 8 previous errors
5066

0 commit comments

Comments
 (0)