From 6100743842ace6db859edfeed9959ac941210c2b Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Tue, 19 Jan 2016 08:40:07 +0100 Subject: [PATCH] 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. --- src/librustc/middle/check_match.rs | 40 ++++++++++--------- .../non-exhaustive-pattern-witness.rs | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 8e5c5788201c..2d882b4c97d8 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -368,31 +368,34 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) { match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { UsefulWithWitness(pats) => { - let witness = match &pats[..] { - [ref witness] => &**witness, - [] => DUMMY_WILD_PAT, - _ => unreachable!() + let witnesses = match &pats[..] { + [] => vec![DUMMY_WILD_PAT], + [p..] => { + p.iter().map(|w| &**w ).collect() + } }; match source { hir::MatchSource::ForLoopDesugar => { - // `witness` has the form `Some()`, peel off the `Some` - let witness = match witness.node { + // `witnesses[0]` has the form `Some()`, peel off the `Some` + let witness = match witnesses[0].node { hir::PatEnum(_, Some(ref pats)) => match &pats[..] { [ref pat] => &**pat, _ => unreachable!(), }, _ => unreachable!(), }; - span_err!(cx.tcx.sess, sp, E0297, "refutable pattern in `for` loop binding: \ `{}` not covered", pat_to_string(witness)); }, _ => { + let pattern_strings: Vec<_> = witnesses.iter().map(|w| { + pat_to_string(w) + }).take(10).collect(); span_err!(cx.tcx.sess, sp, E0004, "non-exhaustive patterns: `{}` not covered", - pat_to_string(witness) + pattern_strings.join("`, `") ); }, } @@ -594,14 +597,14 @@ impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> { } } -fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, - left_ty: Ty, max_slice_length: usize) -> Option { +fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, + left_ty: Ty, max_slice_length: usize) -> Vec { let used_constructors: Vec = rows.iter() .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length)) .collect(); all_constructors(cx, left_ty, max_slice_length) .into_iter() - .find(|c| !used_constructors.contains(c)) + .filter(|c| !used_constructors.contains(c)).collect() } /// This determines the set of all possible constructors of a pattern matching @@ -680,8 +683,8 @@ fn is_useful(cx: &MatchCheckCtxt, let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length); if constructors.is_empty() { - match missing_constructor(cx, matrix, left_ty, max_slice_length) { - None => { + match &missing_constructors(cx, matrix, left_ty, max_slice_length)[..] { + [] => { all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| { match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) { UsefulWithWitness(pats) => UsefulWithWitness({ @@ -701,7 +704,7 @@ fn is_useful(cx: &MatchCheckCtxt, }).find(|result| result != &NotUseful).unwrap_or(NotUseful) }, - Some(constructor) => { + [constructors..] => { let matrix = rows.iter().filter_map(|r| { if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) { Some(r[1..].to_vec()) @@ -711,10 +714,11 @@ fn is_useful(cx: &MatchCheckCtxt, }).collect(); match is_useful(cx, &matrix, &v[1..], witness) { UsefulWithWitness(pats) => { - let arity = constructor_arity(cx, &constructor, left_ty); - let wild_pats = vec![DUMMY_WILD_PAT; arity]; - let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty); - let mut new_pats = vec![enum_pat]; + let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| { + let arity = constructor_arity(cx, &constructor, left_ty); + let wild_pats = vec![DUMMY_WILD_PAT; arity]; + construct_witness(cx, &constructor, wild_pats, left_ty) + }).collect(); new_pats.extend(pats); UsefulWithWitness(new_pats) }, diff --git a/src/test/compile-fail/non-exhaustive-pattern-witness.rs b/src/test/compile-fail/non-exhaustive-pattern-witness.rs index 146265bf0e15..62e61e8bf59f 100644 --- a/src/test/compile-fail/non-exhaustive-pattern-witness.rs +++ b/src/test/compile-fail/non-exhaustive-pattern-witness.rs @@ -34,7 +34,7 @@ fn struct_with_a_nested_enum_and_vector() { fn enum_with_multiple_missing_variants() { match Color::Red { - //~^ ERROR non-exhaustive patterns: `Red` not covered + //~^ ERROR non-exhaustive patterns: `Red`, `Green` not covered Color::CustomRGBA { .. } => () } }