From b51698ad60ecad793ac745be676d3f059bea4b80 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 21:54:55 +0200 Subject: [PATCH] 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. --- src/librustc_const_eval/check_match.rs | 23 ++++++++++-- src/test/compile-fail/issue-31221.rs | 49 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-31221.rs diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5883013ac72f2..adc158b323c91 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 0000000000000..2b3df9ad1d83b --- /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 or the MIT license +// , 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 + }; +}