Skip to content

Commit aba11b3

Browse files
committed
Auto merge of #31020 - regexident:fix_16884, r=brson
Changes error message from displaying first found missing constructor witness to showing up to 10, if necessary. Fixes issue #16884.
2 parents a186eb2 + 2c7a19a commit aba11b3

File tree

2 files changed

+96
-58
lines changed

2 files changed

+96
-58
lines changed

src/librustc/middle/check_match.rs

+64-50
Original file line numberDiff line numberDiff line change
@@ -368,31 +368,46 @@ 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 = if pats.is_empty() {
372+
vec![DUMMY_WILD_PAT]
373+
} else {
374+
pats.iter().map(|w| &**w ).collect()
375375
};
376376
match source {
377377
hir::MatchSource::ForLoopDesugar => {
378-
// `witness` has the form `Some(<head>)`, peel off the `Some`
379-
let witness = match witness.node {
378+
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
379+
let witness = match witnesses[0].node {
380380
hir::PatEnum(_, Some(ref pats)) => match &pats[..] {
381381
[ref pat] => &**pat,
382382
_ => unreachable!(),
383383
},
384384
_ => unreachable!(),
385385
};
386-
387386
span_err!(cx.tcx.sess, sp, E0297,
388387
"refutable pattern in `for` loop binding: \
389388
`{}` not covered",
390389
pat_to_string(witness));
391390
},
392391
_ => {
392+
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
393+
pat_to_string(w)
394+
}).collect();
395+
const LIMIT: usize = 3;
396+
let joined_patterns = match pattern_strings.len() {
397+
0 => unreachable!(),
398+
1 => format!("`{}`", pattern_strings[0]),
399+
2...LIMIT => {
400+
let (tail, head) = pattern_strings.split_last().unwrap();
401+
format!("`{}`", head.join("`, `") + "` and `" + tail)
402+
},
403+
_ => {
404+
let (head, tail) = pattern_strings.split_at(LIMIT);
405+
format!("`{}` and {} more", head.join("`, `"), tail.len())
406+
}
407+
};
393408
span_err!(cx.tcx.sess, sp, E0004,
394-
"non-exhaustive patterns: `{}` not covered",
395-
pat_to_string(witness)
409+
"non-exhaustive patterns: {} not covered",
410+
joined_patterns
396411
);
397412
},
398413
}
@@ -594,14 +609,15 @@ impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> {
594609
}
595610
}
596611

597-
fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
598-
left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
612+
fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
613+
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
599614
let used_constructors: Vec<Constructor> = rows.iter()
600615
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
601616
.collect();
602617
all_constructors(cx, left_ty, max_slice_length)
603618
.into_iter()
604-
.find(|c| !used_constructors.contains(c))
619+
.filter(|c| !used_constructors.contains(c))
620+
.collect()
605621
}
606622

607623
/// This determines the set of all possible constructors of a pattern matching
@@ -680,46 +696,44 @@ fn is_useful(cx: &MatchCheckCtxt,
680696

681697
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
682698
if constructors.is_empty() {
683-
match missing_constructor(cx, matrix, left_ty, max_slice_length) {
684-
None => {
685-
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
686-
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
687-
UsefulWithWitness(pats) => UsefulWithWitness({
688-
let arity = constructor_arity(cx, &c, left_ty);
689-
let mut result = {
690-
let pat_slice = &pats[..];
691-
let subpats: Vec<_> = (0..arity).map(|i| {
692-
pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
693-
}).collect();
694-
vec![construct_witness(cx, &c, subpats, left_ty)]
695-
};
696-
result.extend(pats.into_iter().skip(arity));
697-
result
698-
}),
699-
result => result
700-
}
701-
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
702-
},
703-
704-
Some(constructor) => {
705-
let matrix = rows.iter().filter_map(|r| {
706-
if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
707-
Some(r[1..].to_vec())
708-
} else {
709-
None
710-
}
711-
}).collect();
712-
match is_useful(cx, &matrix, &v[1..], witness) {
713-
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];
718-
new_pats.extend(pats);
719-
UsefulWithWitness(new_pats)
720-
},
699+
let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
700+
if constructors.is_empty() {
701+
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
702+
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
703+
UsefulWithWitness(pats) => UsefulWithWitness({
704+
let arity = constructor_arity(cx, &c, left_ty);
705+
let mut result = {
706+
let pat_slice = &pats[..];
707+
let subpats: Vec<_> = (0..arity).map(|i| {
708+
pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
709+
}).collect();
710+
vec![construct_witness(cx, &c, subpats, left_ty)]
711+
};
712+
result.extend(pats.into_iter().skip(arity));
713+
result
714+
}),
721715
result => result
722716
}
717+
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
718+
} else {
719+
let matrix = rows.iter().filter_map(|r| {
720+
if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
721+
Some(r[1..].to_vec())
722+
} else {
723+
None
724+
}
725+
}).collect();
726+
match is_useful(cx, &matrix, &v[1..], witness) {
727+
UsefulWithWitness(pats) => {
728+
let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| {
729+
let arity = constructor_arity(cx, &constructor, left_ty);
730+
let wild_pats = vec![DUMMY_WILD_PAT; arity];
731+
construct_witness(cx, &constructor, wild_pats, left_ty)
732+
}).collect();
733+
new_pats.extend(pats);
734+
UsefulWithWitness(new_pats)
735+
},
736+
result => result
723737
}
724738
}
725739
} else {

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

+32-8
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@ struct Foo {
1616
second: Option<[usize; 4]>
1717
}
1818

19-
enum Color {
20-
Red,
21-
Green,
22-
CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
23-
}
24-
2519
fn struct_with_a_nested_enum_and_vector() {
2620
match (Foo { first: true, second: None }) {
2721
//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
@@ -32,10 +26,40 @@ fn struct_with_a_nested_enum_and_vector() {
3226
}
3327
}
3428

35-
fn enum_with_multiple_missing_variants() {
29+
enum Color {
30+
Red,
31+
Green,
32+
CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
33+
}
34+
35+
fn enum_with_single_missing_variant() {
3636
match Color::Red {
3737
//~^ ERROR non-exhaustive patterns: `Red` not covered
38-
Color::CustomRGBA { .. } => ()
38+
Color::CustomRGBA { .. } => (),
39+
Color::Green => ()
40+
}
41+
}
42+
43+
enum Direction {
44+
North, East, South, West
45+
}
46+
47+
fn enum_with_multiple_missing_variants() {
48+
match Direction::North {
49+
//~^ ERROR non-exhaustive patterns: `East`, `South` and `West` not covered
50+
Direction::North => ()
51+
}
52+
}
53+
54+
enum ExcessiveEnum {
55+
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
56+
}
57+
58+
fn enum_with_excessive_missing_variants() {
59+
match ExcessiveEnum::First {
60+
//~^ ERROR `Second`, `Third`, `Fourth` and 8 more not covered
61+
62+
ExcessiveEnum::First => ()
3963
}
4064
}
4165

0 commit comments

Comments
 (0)