Skip to content

Commit 7d4665b

Browse files
committed
check_match: unify check_irrefutable & check_exhaustive more.
1 parent b36a206 commit 7d4665b

19 files changed

+135
-95
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,9 @@ struct PatternContext<'tcx> {
517517
pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
518518

519519
impl<'tcx> Witness<'tcx> {
520-
pub fn single_pattern(&self) -> &Pattern<'tcx> {
520+
pub fn single_pattern(self) -> Pattern<'tcx> {
521521
assert_eq!(self.0.len(), 1);
522-
&self.0[0]
522+
self.0.into_iter().next().unwrap()
523523
}
524524

525525
fn push_wild_constructor<'a>(

src/librustc_mir/hair/pattern/check_match.rs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::_match::{MatchCheckCtxt, Matrix, Witness, expand_pattern, is_useful};
1+
use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
22
use super::_match::Usefulness::*;
33
use super::_match::WitnessPreference::*;
44

@@ -276,26 +276,26 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
276276
expand_pattern(cx, pattern)
277277
]].into_iter().collect();
278278

279-
let witness = match check_not_useful(cx, pattern_ty, &pats) {
279+
let witnesses = match check_not_useful(cx, pattern_ty, &pats) {
280280
Ok(_) => return,
281-
Err((witness, _)) => witness,
281+
Err(err) => err,
282282
};
283283

284-
let pattern_string = witness[0].single_pattern().to_string();
284+
let joined_patterns = joined_uncovered_patterns(&witnesses);
285285
let mut err = struct_span_err!(
286286
self.tcx.sess, pat.span, E0005,
287-
"refutable pattern in {}: `{}` not covered",
288-
origin, pattern_string
287+
"refutable pattern in {}: {} not covered",
288+
origin, joined_patterns
289289
);
290-
err.span_label(pat.span, match pat.node {
291-
PatKind::Path(hir::QPath::Resolved(None, ref path))
292-
if path.segments.len() == 1 && path.segments[0].args.is_none() => {
290+
err.span_label(pat.span, match &pat.node {
291+
PatKind::Path(hir::QPath::Resolved(None, path))
292+
if path.segments.len() == 1 && path.segments[0].args.is_none() => {
293293
format!("interpreted as {} {} pattern, not new variable",
294294
path.res.article(), path.res.descr())
295295
}
296-
_ => format!("pattern `{}` not covered", pattern_string),
296+
_ => pattern_not_convered_label(&witnesses, &joined_patterns),
297297
});
298-
adt_defined_here(cx, pattern_ty.peel_refs(), &mut err);
298+
adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
299299
err.emit();
300300
});
301301
}
@@ -437,11 +437,15 @@ fn check_not_useful(
437437
cx: &mut MatchCheckCtxt<'_, 'tcx>,
438438
ty: Ty<'tcx>,
439439
matrix: &Matrix<'_, 'tcx>,
440-
) -> Result<(), (Vec<Witness<'tcx>>, Pattern<'tcx>)> {
440+
) -> Result<(), Vec<Pattern<'tcx>>> {
441441
let wild_pattern = Pattern { ty, span: DUMMY_SP, kind: box PatternKind::Wild };
442442
match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
443443
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
444-
UsefulWithWitness(pats) => Err((pats, wild_pattern)),
444+
UsefulWithWitness(pats) => Err(if pats.is_empty() {
445+
vec![wild_pattern]
446+
} else {
447+
pats.into_iter().map(|w| w.single_pattern()).collect()
448+
}),
445449
Useful => bug!(),
446450
}
447451
}
@@ -452,42 +456,26 @@ fn check_exhaustive<'tcx>(
452456
sp: Span,
453457
matrix: &Matrix<'_, 'tcx>,
454458
) {
455-
let (pats, wild_pattern) = match check_not_useful(cx, scrut_ty, matrix) {
459+
let witnesses = match check_not_useful(cx, scrut_ty, matrix) {
456460
Ok(_) => return,
457461
Err(err) => err,
458462
};
459463

460-
let witnesses = if pats.is_empty() {
461-
vec![&wild_pattern]
462-
} else {
463-
pats.iter().map(|w| w.single_pattern()).collect()
464-
};
465-
466464
let joined_patterns = joined_uncovered_patterns(&witnesses);
467-
468-
let mut err = create_e0004(cx.tcx.sess, sp, format!(
469-
"non-exhaustive patterns: {} not covered",
470-
joined_patterns,
471-
));
472-
err.span_label(sp, match witnesses.len() {
473-
1 => format!("pattern {} not covered", joined_patterns),
474-
_ => format!("patterns {} not covered", joined_patterns),
475-
});
476-
// point at the definition of non-covered enum variants
477-
let scrut_ty = scrut_ty.peel_refs();
478-
adt_defined_here(cx, scrut_ty, &mut err);
479-
let patterns = witnesses.iter().map(|p| (**p).clone()).collect::<Vec<Pattern<'_>>>();
480-
if patterns.len() < 4 {
481-
for sp in maybe_point_at_variant(scrut_ty, &patterns) {
482-
err.span_label(sp, "not covered");
483-
}
484-
}
485-
err.help("ensure that all possible cases are being handled, \
486-
possibly by adding wildcards or more match arms");
487-
err.emit();
465+
let mut err = create_e0004(
466+
cx.tcx.sess, sp,
467+
format!("non-exhaustive patterns: {} not covered", joined_patterns),
468+
);
469+
err.span_label(sp, pattern_not_convered_label(&witnesses, &joined_patterns));
470+
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
471+
err.help(
472+
"ensure that all possible cases are being handled, \
473+
possibly by adding wildcards or more match arms"
474+
)
475+
.emit();
488476
}
489477

490-
fn joined_uncovered_patterns(witnesses: &[&Pattern<'_>]) -> String {
478+
fn joined_uncovered_patterns(witnesses: &[Pattern<'_>]) -> String {
491479
const LIMIT: usize = 3;
492480
match witnesses {
493481
[] => bug!(),
@@ -504,11 +492,31 @@ fn joined_uncovered_patterns(witnesses: &[&Pattern<'_>]) -> String {
504492
}
505493
}
506494

507-
fn adt_defined_here(cx: &mut MatchCheckCtxt<'_, '_>, ty: Ty<'_>, err: &mut DiagnosticBuilder<'_>) {
495+
fn pattern_not_convered_label(witnesses: &[Pattern<'_>], joined_patterns: &str) -> String {
496+
match witnesses.len() {
497+
1 => format!("pattern {} not covered", joined_patterns),
498+
_ => format!("patterns {} not covered", joined_patterns),
499+
}
500+
}
501+
502+
/// Point at the definition of non-covered `enum` variants.
503+
fn adt_defined_here(
504+
cx: &MatchCheckCtxt<'_, '_>,
505+
err: &mut DiagnosticBuilder<'_>,
506+
ty: Ty<'_>,
507+
witnesses: &[Pattern<'_>],
508+
) {
509+
let ty = ty.peel_refs();
508510
if let ty::Adt(def, _) = ty.sty {
509511
if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
510512
err.span_label(sp, format!("`{}` defined here", ty));
511513
}
514+
515+
if witnesses.len() < 4 {
516+
for sp in maybe_point_at_variant(ty, &witnesses) {
517+
err.span_label(sp, "not covered");
518+
}
519+
}
512520
}
513521
}
514522

src/test/ui/consts/const-match-check.eval1.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
1+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
22
--> $DIR/const-match-check.rs:25:15
33
|
44
LL | A = { let 0 = 0; 0 },
5-
| ^ pattern `std::i32::MIN..=-1i32` not covered
5+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
66

77
error: aborting due to previous error
88

src/test/ui/consts/const-match-check.eval2.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
1+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
22
--> $DIR/const-match-check.rs:31:24
33
|
44
LL | let x: [i32; { let 0 = 0; 0 }] = [];
5-
| ^ pattern `std::i32::MIN..=-1i32` not covered
5+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
66

77
error: aborting due to previous error
88

src/test/ui/consts/const-match-check.matchck.stderr

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
1+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
22
--> $DIR/const-match-check.rs:4:22
33
|
44
LL | const X: i32 = { let 0 = 0; 0 };
5-
| ^ pattern `std::i32::MIN..=-1i32` not covered
5+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
66

7-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
7+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
88
--> $DIR/const-match-check.rs:8:23
99
|
1010
LL | static Y: i32 = { let 0 = 0; 0 };
11-
| ^ pattern `std::i32::MIN..=-1i32` not covered
11+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
1212

13-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
13+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
1414
--> $DIR/const-match-check.rs:13:26
1515
|
1616
LL | const X: i32 = { let 0 = 0; 0 };
17-
| ^ pattern `std::i32::MIN..=-1i32` not covered
17+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
1818

19-
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` not covered
19+
error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
2020
--> $DIR/const-match-check.rs:19:26
2121
|
2222
LL | const X: i32 = { let 0 = 0; 0 };
23-
| ^ pattern `std::i32::MIN..=-1i32` not covered
23+
| ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered
2424

2525
error: aborting due to 4 previous errors
2626

src/test/ui/consts/const-pattern-irrefutable.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use foo::d;
99
const a: u8 = 2;
1010

1111
fn main() {
12-
let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
13-
let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
14-
let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
12+
let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
13+
let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
14+
let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX
1515
fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
1616
}

src/test/ui/consts/const-pattern-irrefutable.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
1+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
22
--> $DIR/const-pattern-irrefutable.rs:12:9
33
|
44
LL | let a = 4;
55
| ^ interpreted as a constant pattern, not new variable
66

7-
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
7+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
88
--> $DIR/const-pattern-irrefutable.rs:13:9
99
|
1010
LL | let c = 4;
1111
| ^ interpreted as a constant pattern, not new variable
1212

13-
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
13+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered
1414
--> $DIR/const-pattern-irrefutable.rs:14:9
1515
|
1616
LL | let d = 4;

src/test/ui/consts/const_let_refutable.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in function argument: `&[]` not covered
1+
error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered
22
--> $DIR/const_let_refutable.rs:3:16
33
|
44
LL | const fn slice([a, b]: &[i32]) -> i32 {
5-
| ^^^^^^ pattern `&[]` not covered
5+
| ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered
66

77
error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
88
--> $DIR/const_let_refutable.rs:4:5

src/test/ui/empty/empty-never-array.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
33
|
44
LL | / enum Helper<T, U> {
55
LL | | T(T, [!; 0]),
6+
| | - not covered
67
LL | | #[allow(dead_code)]
78
LL | | U(U),
89
LL | | }

src/test/ui/for/for-loop-refutable-pattern-error-message.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` not covered
1+
error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered
22
--> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
33
|
44
LL | for &1 in [1].iter() {}
5-
| ^^ pattern `&std::i32::MIN..=0i32` not covered
5+
| ^^ patterns `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-15381.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ fn main() {
22
let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
33

44
for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
5-
//~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
5+
//~^ ERROR refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not
66
println!("y={}", y);
77
//~^ ERROR borrow of possibly-uninitialized variable: `y`
88
}

src/test/ui/issues/issue-15381.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in `for` loop binding: `&[]` not covered
1+
error[E0005]: refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
22
--> $DIR/issue-15381.rs:4:9
33
|
44
LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
5-
| ^^^^^^^^ pattern `&[]` not covered
5+
| ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
66

77
error[E0381]: borrow of possibly-uninitialized variable: `y`
88
--> $DIR/issue-15381.rs:6:26

src/test/ui/issues/issue-31561.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ enum Thing {
66

77
fn main() {
88
let Thing::Foo(y) = Thing::Foo(1);
9-
//~^ ERROR refutable pattern in local binding: `Bar` not covered
9+
//~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered
1010
}

src/test/ui/issues/issue-31561.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
error[E0005]: refutable pattern in local binding: `Bar` not covered
1+
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
22
--> $DIR/issue-31561.rs:8:9
33
|
44
LL | / enum Thing {
55
LL | | Foo(u8),
66
LL | | Bar,
7+
| | --- not covered
78
LL | | Baz
9+
| | --- not covered
810
LL | | }
911
| |_- `Thing` defined here
1012
...
1113
LL | let Thing::Foo(y) = Thing::Foo(1);
12-
| ^^^^^^^^^^^^^ pattern `Bar` not covered
14+
| ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
1315

1416
error: aborting due to previous error
1517

src/test/ui/match/non-exhaustive-defined-here.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ enum E {
1515
//~^ not covered
1616
//~| not covered
1717
//~| not covered
18+
//~| not covered
19+
//~| not covered
20+
//~| not covered
1821
C
1922
//~^ not covered
2023
//~| not covered
2124
//~| not covered
25+
//~| not covered
26+
//~| not covered
27+
//~| not covered
2228
}
2329

2430
fn by_val(e: E) {
@@ -27,23 +33,24 @@ fn by_val(e: E) {
2733
E::A => {}
2834
}
2935

30-
let E::A = e; //~ ERROR refutable pattern in local binding: `B` not covered
36+
let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
3137
}
3238

3339
fn by_ref_once(e: &E) {
3440
match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
3541
E::A => {}
3642
}
3743

38-
let E::A = e; //~ ERROR refutable pattern in local binding: `&B` not covered
44+
let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
3945
}
4046

4147
fn by_ref_thrice(e: & &mut &E) {
4248
match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
4349
E::A => {}
4450
}
4551

46-
let E::A = e; //~ ERROR refutable pattern in local binding: `&&mut &B` not covered
52+
let E::A = e;
53+
//~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
4754
}
4855

4956
enum Opt {

0 commit comments

Comments
 (0)