about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2016-05-01 21:54:55 +0200
committerGeorg Brandl <georg@python.org>2016-05-01 21:58:46 +0200
commitb51698ad60ecad793ac745be676d3f059bea4b80 (patch)
tree5041c36f684223e5af5a8edeb373bf4ee89e6357
parent2a815a26c8ce70e1aede585827c020d9775a8faf (diff)
downloadrust-b51698ad60ecad793ac745be676d3f059bea4b80.tar.gz
rust-b51698ad60ecad793ac745be676d3f059bea4b80.zip
match check: note "catchall" patterns in unreachable error
Caught as catchall patterns are:

* unconditional name bindings
* references to them
* tuple bindings with catchall elements

Fixes #31221.
-rw-r--r--src/librustc_const_eval/check_match.rs23
-rw-r--r--src/test/compile-fail/issue-31221.rs49
2 files changed, 70 insertions, 2 deletions
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 5883013ac72..adc158b323c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -341,7 +341,15 @@ fn check_arms(cx: &MatchCheckCtxt,
                         },
 
                         hir::MatchSource::Normal => {
-                            span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
+                            let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
+                                                           "unreachable pattern");
+                            // if we had a catchall pattern, hint at that
+                            for row in &seen.0 {
+                                if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) {
+                                    span_note!(err, row[0].span, "this pattern matches any value");
+                                }
+                            }
+                            err.emit();
                         },
 
                         hir::MatchSource::TryDesugar => {
@@ -361,7 +369,18 @@ fn check_arms(cx: &MatchCheckCtxt,
     }
 }
 
-fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
+/// Checks for common cases of "catchall" patterns that may not be intended as such.
+fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
+    match p.node {
+        PatKind::Ident(_, _, None) => pat_is_binding(dm, p),
+        PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
+        PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
+        PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)),
+        _ => false
+    }
+}
+
+fn raw_pat(p: &Pat) -> &Pat {
     match p.node {
         PatKind::Ident(_, _, Some(ref s)) => raw_pat(&s),
         _ => p
diff --git a/src/test/compile-fail/issue-31221.rs b/src/test/compile-fail/issue-31221.rs
new file mode 100644
index 00000000000..2b3df9ad1d8
--- /dev/null
+++ b/src/test/compile-fail/issue-31221.rs
@@ -0,0 +1,49 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Enum {
+    Var1,
+    Var2,
+}
+
+fn main() {
+    use Enum::*;
+    let s = Var1;
+    match s {
+        Var1 => (),
+        Var3 => (),
+        //~^ NOTE this pattern matches any value
+        Var2 => (),
+        //~^ ERROR unreachable pattern
+    };
+    match &s {
+        &Var1 => (),
+        &Var3 => (),
+        //~^ NOTE this pattern matches any value
+        &Var2 => (),
+        //~^ ERROR unreachable pattern
+    };
+    let t = (Var1, Var1);
+    match t {
+        (Var1, b) => (),
+        (c, d) => (),
+        //~^ NOTE this pattern matches any value
+        anything => ()
+        //~^ ERROR unreachable pattern
+    };
+    // `_` need not emit a note, it is pretty obvious already.
+    let t = (Var1, Var1);
+    match t {
+        (Var1, b) => (),
+        _ => (),
+        anything => ()
+        //~^ ERROR unreachable pattern
+    };
+}