Skip to content

Commit 0df221e

Browse files
committed
rustc: provide more precise information about refutable patterns.
The compiler now points exactly which part(s) of a pattern are refutable, rather than just highlighting the whole pattern.
1 parent f2a1378 commit 0df221e

File tree

2 files changed

+73
-25
lines changed

2 files changed

+73
-25
lines changed

src/librustc/middle/check_match.rs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -863,13 +863,17 @@ fn default(cx: &MatchCheckCtxt, r: &[@Pat]) -> Option<Vec<@Pat> > {
863863

864864
fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
865865
visit::walk_local(cx, loc, ());
866-
if is_refutable(cx, loc.pat) {
867-
let name = match loc.source {
868-
LocalLet => "local",
869-
LocalFor => "`for` loop"
870-
};
871866

872-
cx.tcx.sess.span_err(loc.pat.span,
867+
let name = match loc.source {
868+
LocalLet => "local",
869+
LocalFor => "`for` loop"
870+
};
871+
872+
let mut spans = vec![];
873+
find_refutable(cx, loc.pat, &mut spans);
874+
875+
for span in spans.iter() {
876+
cx.tcx.sess.span_err(*span,
873877
format!("refutable pattern in {} binding", name).as_slice());
874878
}
875879

@@ -884,53 +888,65 @@ fn check_fn(cx: &mut MatchCheckCtxt,
884888
sp: Span) {
885889
visit::walk_fn(cx, kind, decl, body, sp, ());
886890
for input in decl.inputs.iter() {
887-
if is_refutable(cx, input.pat) {
888-
cx.tcx.sess.span_err(input.pat.span,
891+
let mut spans = vec![];
892+
find_refutable(cx, input.pat, &mut spans);
893+
894+
for span in spans.iter() {
895+
cx.tcx.sess.span_err(*span,
889896
"refutable pattern in function argument");
890897
}
891898
}
892899
}
893900

894-
fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat) -> bool {
901+
fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec<Span>) {
902+
macro_rules! this_pattern {
903+
() => {
904+
{
905+
spans.push(pat.span);
906+
return
907+
}
908+
}
909+
}
895910
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
896911
match opt_def {
897912
Some(DefVariant(enum_id, _, _)) => {
898913
if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
899-
return true;
914+
this_pattern!()
900915
}
901916
}
902-
Some(DefStatic(..)) => return true,
917+
Some(DefStatic(..)) => this_pattern!(),
903918
_ => ()
904919
}
905920

906921
match pat.node {
907922
PatUniq(sub) | PatRegion(sub) | PatIdent(_, _, Some(sub)) => {
908-
is_refutable(cx, sub)
923+
find_refutable(cx, sub, spans)
909924
}
910-
PatWild | PatWildMulti | PatIdent(_, _, None) => { false }
925+
PatWild | PatWildMulti | PatIdent(_, _, None) => {}
911926
PatLit(lit) => {
912927
match lit.node {
913928
ExprLit(lit) => {
914929
match lit.node {
915-
LitNil => false, // `()`
916-
_ => true,
930+
LitNil => {} // `()`
931+
_ => this_pattern!(),
917932
}
918933
}
919-
_ => true,
934+
_ => this_pattern!(),
920935
}
921936
}
922-
PatRange(_, _) => { true }
937+
PatRange(_, _) => { this_pattern!() }
923938
PatStruct(_, ref fields, _) => {
924-
fields.iter().any(|f| is_refutable(cx, f.pat))
925-
}
926-
PatTup(ref elts) => {
927-
elts.iter().any(|elt| is_refutable(cx, *elt))
939+
for f in fields.iter() {
940+
find_refutable(cx, f.pat, spans);
941+
}
928942
}
929-
PatEnum(_, Some(ref args)) => {
930-
args.iter().any(|a| is_refutable(cx, *a))
943+
PatTup(ref elts) | PatEnum(_, Some(ref elts))=> {
944+
for elt in elts.iter() {
945+
find_refutable(cx, *elt, spans)
946+
}
931947
}
932-
PatEnum(_,_) => { false }
933-
PatVec(..) => { true }
948+
PatEnum(_,_) => {}
949+
PatVec(..) => { this_pattern!() }
934950
}
935951
}
936952

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2014 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+
12+
fn func(
13+
(
14+
1, //~ ERROR refutable pattern in function argument
15+
(
16+
Some( //~ ERROR refutable pattern in function argument
17+
1), // nested, so no warning.
18+
2..3 //~ ERROR refutable pattern in function argument
19+
)
20+
): (int, (Option<int>, int))
21+
) {}
22+
23+
fn main() {
24+
let (
25+
1, //~ ERROR refutable pattern in local binding
26+
(
27+
Some( //~ ERROR refutable pattern in local binding
28+
1), // nested, so no warning.
29+
2..3 //~ ERROR refutable pattern in local binding
30+
)
31+
) = (1, (None, 2));
32+
}

0 commit comments

Comments
 (0)