Skip to content

Commit 6100743

Browse files
committed
Improve error message for non-exhaustive patterns
Changes error message from displaying first found missing constructor witness to showing up to 10, if necessary. Fixes issue #16884.
1 parent 7a7307e commit 6100743

File tree

2 files changed

+23
-19
lines changed

2 files changed

+23
-19
lines changed

src/librustc/middle/check_match.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -368,31 +368,34 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
368368
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) {
369369
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
370370
UsefulWithWitness(pats) => {
371-
let witness = match &pats[..] {
372-
[ref witness] => &**witness,
373-
[] => DUMMY_WILD_PAT,
374-
_ => unreachable!()
371+
let witnesses = match &pats[..] {
372+
[] => vec![DUMMY_WILD_PAT],
373+
[p..] => {
374+
p.iter().map(|w| &**w ).collect()
375+
}
375376
};
376377
match source {
377378
hir::MatchSource::ForLoopDesugar => {
378-
// `witness` has the form `Some(<head>)`, peel off the `Some`
379-
let witness = match witness.node {
379+
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
380+
let witness = match witnesses[0].node {
380381
hir::PatEnum(_, Some(ref pats)) => match &pats[..] {
381382
[ref pat] => &**pat,
382383
_ => unreachable!(),
383384
},
384385
_ => unreachable!(),
385386
};
386-
387387
span_err!(cx.tcx.sess, sp, E0297,
388388
"refutable pattern in `for` loop binding: \
389389
`{}` not covered",
390390
pat_to_string(witness));
391391
},
392392
_ => {
393+
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
394+
pat_to_string(w)
395+
}).take(10).collect();
393396
span_err!(cx.tcx.sess, sp, E0004,
394397
"non-exhaustive patterns: `{}` not covered",
395-
pat_to_string(witness)
398+
pattern_strings.join("`, `")
396399
);
397400
},
398401
}
@@ -594,14 +597,14 @@ impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> {
594597
}
595598
}
596599

597-
fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
598-
left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
600+
fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
601+
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
599602
let used_constructors: Vec<Constructor> = rows.iter()
600603
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
601604
.collect();
602605
all_constructors(cx, left_ty, max_slice_length)
603606
.into_iter()
604-
.find(|c| !used_constructors.contains(c))
607+
.filter(|c| !used_constructors.contains(c)).collect()
605608
}
606609

607610
/// This determines the set of all possible constructors of a pattern matching
@@ -680,8 +683,8 @@ fn is_useful(cx: &MatchCheckCtxt,
680683

681684
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
682685
if constructors.is_empty() {
683-
match missing_constructor(cx, matrix, left_ty, max_slice_length) {
684-
None => {
686+
match &missing_constructors(cx, matrix, left_ty, max_slice_length)[..] {
687+
[] => {
685688
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
686689
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
687690
UsefulWithWitness(pats) => UsefulWithWitness({
@@ -701,7 +704,7 @@ fn is_useful(cx: &MatchCheckCtxt,
701704
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
702705
},
703706

704-
Some(constructor) => {
707+
[constructors..] => {
705708
let matrix = rows.iter().filter_map(|r| {
706709
if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
707710
Some(r[1..].to_vec())
@@ -711,10 +714,11 @@ fn is_useful(cx: &MatchCheckCtxt,
711714
}).collect();
712715
match is_useful(cx, &matrix, &v[1..], witness) {
713716
UsefulWithWitness(pats) => {
714-
let arity = constructor_arity(cx, &constructor, left_ty);
715-
let wild_pats = vec![DUMMY_WILD_PAT; arity];
716-
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
717-
let mut new_pats = vec![enum_pat];
717+
let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| {
718+
let arity = constructor_arity(cx, &constructor, left_ty);
719+
let wild_pats = vec![DUMMY_WILD_PAT; arity];
720+
construct_witness(cx, &constructor, wild_pats, left_ty)
721+
}).collect();
718722
new_pats.extend(pats);
719723
UsefulWithWitness(new_pats)
720724
},

src/test/compile-fail/non-exhaustive-pattern-witness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn struct_with_a_nested_enum_and_vector() {
3434

3535
fn enum_with_multiple_missing_variants() {
3636
match Color::Red {
37-
//~^ ERROR non-exhaustive patterns: `Red` not covered
37+
//~^ ERROR non-exhaustive patterns: `Red`, `Green` not covered
3838
Color::CustomRGBA { .. } => ()
3939
}
4040
}

0 commit comments

Comments
 (0)