]> git.lizzy.rs Git - rust.git/commitdiff
Improve error message for non-exhaustive patterns
authorVincent Esche <regexident@gmail.com>
Tue, 19 Jan 2016 07:40:07 +0000 (08:40 +0100)
committerVincent Esche <regexident@gmail.com>
Tue, 19 Jan 2016 07:42:55 +0000 (08:42 +0100)
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
src/test/compile-fail/non-exhaustive-pattern-witness.rs

index 8e5c5788201cccb8e45e9928050d7dc4be9d4c29..2d882b4c97d88d2334b2cd7983e65ffa02bd0119 100644 (file)
@@ -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(<head>)`, peel off the `Some`
-                    let witness = match witness.node {
+                    // `witnesses[0]` has the form `Some(<head>)`, 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 @@ fn variant_of_ctor(&self,
     }
 }
 
-fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
-                       left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
+fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
+                       left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
     let used_constructors: Vec<Constructor> = 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)
                     },
index 146265bf0e1508bfaa7755642f04d3c43a5a12d6..62e61e8bf59f7ee67c1b0849407b045aab92ec48 100644 (file)
@@ -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 { .. } => ()
     }
 }