Skip to content

Commit b51698a

Browse files
committed
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.
1 parent 2a815a2 commit b51698a

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

src/librustc_const_eval/check_match.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,15 @@ fn check_arms(cx: &MatchCheckCtxt,
341341
},
342342

343343
hir::MatchSource::Normal => {
344-
span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
344+
let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
345+
"unreachable pattern");
346+
// if we had a catchall pattern, hint at that
347+
for row in &seen.0 {
348+
if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) {
349+
span_note!(err, row[0].span, "this pattern matches any value");
350+
}
351+
}
352+
err.emit();
345353
},
346354

347355
hir::MatchSource::TryDesugar => {
@@ -361,7 +369,18 @@ fn check_arms(cx: &MatchCheckCtxt,
361369
}
362370
}
363371

364-
fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
372+
/// Checks for common cases of "catchall" patterns that may not be intended as such.
373+
fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
374+
match p.node {
375+
PatKind::Ident(_, _, None) => pat_is_binding(dm, p),
376+
PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
377+
PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
378+
PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)),
379+
_ => false
380+
}
381+
}
382+
383+
fn raw_pat(p: &Pat) -> &Pat {
365384
match p.node {
366385
PatKind::Ident(_, _, Some(ref s)) => raw_pat(&s),
367386
_ => p

src/test/compile-fail/issue-31221.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
enum Enum {
12+
Var1,
13+
Var2,
14+
}
15+
16+
fn main() {
17+
use Enum::*;
18+
let s = Var1;
19+
match s {
20+
Var1 => (),
21+
Var3 => (),
22+
//~^ NOTE this pattern matches any value
23+
Var2 => (),
24+
//~^ ERROR unreachable pattern
25+
};
26+
match &s {
27+
&Var1 => (),
28+
&Var3 => (),
29+
//~^ NOTE this pattern matches any value
30+
&Var2 => (),
31+
//~^ ERROR unreachable pattern
32+
};
33+
let t = (Var1, Var1);
34+
match t {
35+
(Var1, b) => (),
36+
(c, d) => (),
37+
//~^ NOTE this pattern matches any value
38+
anything => ()
39+
//~^ ERROR unreachable pattern
40+
};
41+
// `_` need not emit a note, it is pretty obvious already.
42+
let t = (Var1, Var1);
43+
match t {
44+
(Var1, b) => (),
45+
_ => (),
46+
anything => ()
47+
//~^ ERROR unreachable pattern
48+
};
49+
}

0 commit comments

Comments
 (0)