Skip to content

Commit abce42a

Browse files
author
Jakub Wieczorek
committed
Address review comments
1 parent 76f7eee commit abce42a

10 files changed

+153
-66
lines changed

src/librustc/middle/check_match.rs

+58-48
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ impl Usefulness {
5151
}
5252

5353
fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
54-
ty::with_path(tcx, id, |path| Path {
54+
ty::with_path(tcx, id, |mut path| Path {
5555
global: false,
56-
segments: path.map(|elem| PathSegment {
56+
segments: path.last().map(|elem| PathSegment {
5757
identifier: Ident::new(elem.name()),
5858
lifetimes: vec!(),
5959
types: OwnedSlice::empty()
60-
}).collect(),
60+
}).move_iter().collect(),
6161
span: DUMMY_SP,
6262
})
6363
}
@@ -100,10 +100,11 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
100100
arm.pats.as_slice());
101101
}
102102

103+
// Second, check for unreachable arms.
103104
check_arms(cx, arms.as_slice());
104-
/* Check for exhaustiveness */
105-
// Check for empty enum, because is_useful only works on inhabited
106-
// types.
105+
106+
// Finally, check if the whole match expression is exhaustive.
107+
// Check for empty enum, because is_useful only works on inhabited types.
107108
let pat_ty = node_id_to_type(cx.tcx, scrut.id);
108109
if (*arms).is_empty() {
109110
if !type_is_empty(cx.tcx, pat_ty) {
@@ -180,11 +181,11 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
180181
}
181182
Useful(pats) => {
182183
let witness = match pats.as_slice() {
183-
[ref witness] => witness.clone(),
184+
[witness] => witness,
184185
[] => wild(),
185186
_ => unreachable!()
186187
};
187-
let msg = format!("non-exhaustive patterns: {0} not covered", pat_to_str(&*witness));
188+
let msg = format!("non-exhaustive patterns: `{0}` not covered", pat_to_str(&*witness));
188189
cx.tcx.sess.span_err(sp, msg.as_slice());
189190
}
190191
}
@@ -193,7 +194,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
193194
#[deriving(Clone, PartialEq)]
194195
enum ctor {
195196
single,
196-
variant(DefId),
197+
variant(DefId /* variant */, bool /* is_structure */),
197198
val(const_val),
198199
range(const_val, const_val),
199200
vec(uint)
@@ -215,23 +216,23 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &ctor, pats: Vec<Gc<Pat>>, lty:
215216
let pat = match ty::get(lty).sty {
216217
ty::ty_tup(_) => PatTup(pats),
217218

218-
ty::ty_enum(_, _) => {
219-
let vid = match ctor {
220-
&variant(vid) => vid,
221-
_ => unreachable!()
219+
ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
220+
let (vid, is_structure) = match ctor {
221+
&variant(vid, is_structure) => (vid, is_structure),
222+
_ => (cid, true)
222223
};
223-
PatEnum(def_to_path(cx.tcx, vid), Some(pats))
224-
},
225-
226-
ty::ty_struct(cid, _) => {
227-
let fields = ty::lookup_struct_fields(cx.tcx, cid);
228-
let field_pats = fields.move_iter()
229-
.zip(pats.iter())
230-
.map(|(field, pat)| FieldPat {
231-
ident: Ident::new(field.name),
232-
pat: pat.clone()
233-
}).collect();
234-
PatStruct(def_to_path(cx.tcx, cid), field_pats, false)
224+
if is_structure {
225+
let fields = ty::lookup_struct_fields(cx.tcx, vid);
226+
let field_pats = fields.move_iter()
227+
.zip(pats.iter())
228+
.map(|(field, pat)| FieldPat {
229+
ident: Ident::new(field.name),
230+
pat: pat.clone()
231+
}).collect();
232+
PatStruct(def_to_path(cx.tcx, vid), field_pats, false)
233+
} else {
234+
PatEnum(def_to_path(cx.tcx, vid), Some(pats))
235+
}
235236
},
236237

237238
ty::ty_rptr(_, ty::mt { ty: ty, .. }) => {
@@ -307,7 +308,10 @@ fn all_constructors(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Vec<ctor
307308
},
308309

309310
ty::ty_enum(eid, _) =>
310-
ty::enum_variants(cx.tcx, eid).iter().map(|va| variant(va.id)).collect(),
311+
ty::enum_variants(cx.tcx, eid)
312+
.iter()
313+
.map(|va| variant(va.id, va.arg_names.is_some()))
314+
.collect(),
311315

312316
ty::ty_vec(_, None) =>
313317
vec_constructors(m),
@@ -389,8 +393,8 @@ fn is_useful(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
389393
},
390394

391395
Some(ctor) => {
392-
let matrix = &m.iter().filter_map(|r| default(cx, r.as_slice())).collect();
393-
match is_useful(cx, matrix, v.tail(), witness) {
396+
let matrix = m.iter().filter_map(|r| default(cx, r.as_slice())).collect();
397+
match is_useful(cx, &matrix, v.tail(), witness) {
394398
Useful(pats) => Useful(match witness {
395399
ConstructWitness => {
396400
let arity = constructor_arity(cx, &ctor, left_ty);
@@ -424,19 +428,28 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
424428
fn pat_ctor_id(cx: &MatchCheckCtxt, left_ty: ty::t, p: Gc<Pat>) -> Option<ctor> {
425429
let pat = raw_pat(p);
426430
match pat.node {
427-
PatIdent(..) | PatEnum(..) | PatStruct(..) =>
431+
PatIdent(..) =>
428432
match cx.tcx.def_map.borrow().find(&pat.id) {
429433
Some(&DefStatic(did, false)) => {
430434
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
431435
Some(val(eval_const_expr(cx.tcx, &*const_expr)))
432436
},
433-
Some(&DefVariant(_, id, _)) =>
434-
Some(variant(id)),
435-
_ => match pat.node {
436-
PatEnum(..) | PatStruct(..) => Some(single),
437-
PatIdent(..) => None,
438-
_ => unreachable!()
439-
}
437+
Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
438+
_ => None
439+
},
440+
PatEnum(..) =>
441+
match cx.tcx.def_map.borrow().find(&pat.id) {
442+
Some(&DefStatic(did, false)) => {
443+
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
444+
Some(val(eval_const_expr(cx.tcx, &*const_expr)))
445+
},
446+
Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
447+
_ => Some(single)
448+
},
449+
PatStruct(..) =>
450+
match cx.tcx.def_map.borrow().find(&pat.id) {
451+
Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
452+
_ => Some(single)
440453
},
441454
PatLit(expr) =>
442455
Some(val(eval_const_expr(cx.tcx, &*expr))),
@@ -485,7 +498,7 @@ fn constructor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
485498
},
486499
ty::ty_enum(eid, _) => {
487500
match *ctor {
488-
variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
501+
variant(id, _) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
489502
_ => unreachable!()
490503
}
491504
}
@@ -532,13 +545,10 @@ fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
532545
&PatIdent(_, _, _) => {
533546
let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
534547
match opt_def {
535-
Some(DefVariant(_, id, _)) => {
536-
if variant(id) == *ctor_id {
537-
Some(vec!())
538-
} else {
539-
None
540-
}
541-
}
548+
Some(DefVariant(_, id, _)) => match *ctor_id {
549+
variant(vid, _) if vid == id => Some(vec!()),
550+
_ => None
551+
},
542552
Some(DefStatic(did, _)) => {
543553
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
544554
let e_v = eval_const_expr(cx.tcx, &*const_expr);
@@ -571,7 +581,7 @@ fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
571581
}
572582
}
573583
}
574-
DefVariant(_, id, _) if variant(id) != *ctor_id => None,
584+
DefVariant(_, id, _) if variant(id, false) != *ctor_id => None,
575585
DefVariant(..) | DefFn(..) | DefStruct(..) => {
576586
Some(match args {
577587
&Some(ref args) => args.clone(),
@@ -586,7 +596,7 @@ fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
586596
// Is this a struct or an enum variant?
587597
let def = cx.tcx.def_map.borrow().get_copy(pat_id);
588598
let class_id = match def {
589-
DefVariant(_, variant_id, _) => if variant(variant_id) == *ctor_id {
599+
DefVariant(_, variant_id, _) => if *ctor_id == variant(variant_id, true) {
590600
Some(variant_id)
591601
} else {
592602
None
@@ -687,7 +697,7 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
687697
match is_refutable(cx, loc.pat) {
688698
Some(pat) => {
689699
let msg = format!(
690-
"refutable pattern in {} binding: {} not covered",
700+
"refutable pattern in {} binding: `{}` not covered",
691701
name, pat_to_str(&*pat)
692702
);
693703
cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
@@ -709,7 +719,7 @@ fn check_fn(cx: &mut MatchCheckCtxt,
709719
match is_refutable(cx, input.pat) {
710720
Some(pat) => {
711721
let msg = format!(
712-
"refutable pattern in function argument: {} not covered",
722+
"refutable pattern in function argument: `{}` not covered",
713723
pat_to_str(&*pat)
714724
);
715725
cx.tcx.sess.span_err(input.pat.span, msg.as_slice());

src/librustc/middle/typeck/check/_match.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -701,10 +701,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
701701
Some(format!("a fixed vector pattern of size {}", min_len)),
702702

703703
_ => None
704-
}).and_then(|message| {
705-
check_err(message);
706-
Some(())
707-
});
704+
}).map(check_err);
708705

709706
for elt in before.iter() {
710707
check_pat(pcx, &**elt, elt_type);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
fn foo(a: Option<uint>, b: Option<uint>) {
1212
match (a,b) {
13-
//~^ ERROR: non-exhaustive patterns: (core::option::None, core::option::None) not covered
13+
//~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
1414
(Some(a), Some(b)) if a == b => { }
1515
(Some(_), None) |
1616
(None, Some(_)) => { }

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
fn main() {
1212
let tup = (true, true);
13-
println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: (true, false) not covered
13+
println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
1414
(false, false) => "foo",
1515
(false, true) => "bar",
1616
(true, true) => "baz"

src/test/compile-fail/non-exhaustive-match-nested.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ enum u { c, d }
1313

1414
fn main() {
1515
let x = a(c);
16-
match x { //~ ERROR non-exhaustive patterns: a(c) not covered
16+
match x { //~ ERROR non-exhaustive patterns: `a(c)` not covered
1717
a(d) => { fail!("hello"); }
1818
b => { fail!("goodbye"); }
1919
}

src/test/compile-fail/non-exhaustive-match.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ enum t { a, b, }
1212

1313
fn main() {
1414
let x = a;
15-
match x { b => { } } //~ ERROR non-exhaustive patterns: a not covered
16-
match true { //~ ERROR non-exhaustive patterns: false not covered
15+
match x { b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
16+
match true { //~ ERROR non-exhaustive patterns: `false` not covered
1717
true => {}
1818
}
19-
match Some(10) { //~ ERROR non-exhaustive patterns: core::option::Some(_) not covered
19+
match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
2020
None => {}
2121
}
22-
match (2, 3, 4) { //~ ERROR non-exhaustive patterns: (_, _, _) not covered
22+
match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
2323
(_, _, 4) => {}
2424
}
25-
match (a, a) { //~ ERROR non-exhaustive patterns: (a, a) not covered
25+
match (a, a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
2626
(a, b) => {}
2727
(b, a) => {}
2828
}
29-
match a { //~ ERROR non-exhaustive patterns: b not covered
29+
match a { //~ ERROR non-exhaustive patterns: `b` not covered
3030
a => {}
3131
}
3232
// This is exhaustive, though the algorithm got it wrong at one point
@@ -37,7 +37,7 @@ fn main() {
3737
}
3838
let vec = vec!(Some(42), None, Some(21));
3939
let vec: &[Option<int>] = vec.as_slice();
40-
match vec { //~ ERROR non-exhaustive patterns: [] not covered
40+
match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
4141
[Some(..), None, ..tail] => {}
4242
[Some(..), Some(..), ..tail] => {}
4343
[None] => {}
@@ -50,7 +50,7 @@ fn main() {
5050
}
5151
let vec = vec!(0.5);
5252
let vec: &[f32] = vec.as_slice();
53-
match vec { //~ ERROR non-exhaustive patterns: [_, _, _, _] not covered
53+
match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
5454
[0.1, 0.2, 0.3] => (),
5555
[0.1, 0.2] => (),
5656
[0.1] => (),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
#![feature(struct_variant)]
12+
13+
struct Foo {
14+
first: bool,
15+
second: Option<[uint, ..4]>
16+
}
17+
18+
enum Color {
19+
Red,
20+
Green,
21+
CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
22+
}
23+
24+
fn struct_with_a_nested_enum_and_vector() {
25+
match Foo { first: true, second: None } {
26+
//~^ ERROR non-exhaustive patterns: `Foo{first: false, second: Some([_, _, _, _])}` not covered
27+
Foo { first: true, second: None } => (),
28+
Foo { first: true, second: Some(_) } => (),
29+
Foo { first: false, second: None } => (),
30+
Foo { first: false, second: Some([1u, 2u, 3u, 4u]) } => ()
31+
}
32+
}
33+
34+
fn enum_with_multiple_missing_variants() {
35+
match Red {
36+
//~^ ERROR non-exhaustive patterns: `Red` not covered
37+
CustomRGBA { .. } => ()
38+
}
39+
}
40+
41+
fn enum_struct_variant() {
42+
match Red {
43+
//~^ ERROR non-exhaustive patterns: `CustomRGBA{a: true, r: _, g: _, b: _}` not covered
44+
Red => (),
45+
Green => (),
46+
CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
47+
CustomRGBA { a: false, r: _, g: _, b: _ } => ()
48+
}
49+
}
50+
51+
enum Enum {
52+
First,
53+
Second(bool)
54+
}
55+
56+
fn vectors_with_nested_enums() {
57+
let x: &'static [Enum] = [First, Second(false)];
58+
match x {
59+
//~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
60+
[] => (),
61+
[_] => (),
62+
[First, _] => (),
63+
[Second(true), First] => (),
64+
[Second(true), Second(true)] => (),
65+
[Second(false), _] => (),
66+
[_, _, ..tail, _] => ()
67+
}
68+
}
69+
70+
fn main() {
71+
struct_with_a_nested_enum_and_vector();
72+
enum_with_multiple_missing_variants();
73+
enum_struct_variant();
74+
}

src/test/compile-fail/refutable-pattern-errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111

1212
fn func((1, (Some(1), 2..3)): (int, (Option<int>, int))) { }
13-
//~^ ERROR refutable pattern in function argument: (_, _) not covered
13+
//~^ ERROR refutable pattern in function argument: `(_, _)` not covered
1414

1515
fn main() {
1616
let (1, (Some(1), 2..3)) = (1, (None, 2));
17-
//~^ ERROR refutable pattern in local binding: (_, _) not covered
17+
//~^ ERROR refutable pattern in local binding: `(_, _)` not covered
1818
}

src/test/compile-fail/refutable-pattern-in-fn-arg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
fn main() {
1212
let f = |3: int| println!("hello");
13-
//~^ ERROR refutable pattern in function argument: _ not covered
13+
//~^ ERROR refutable pattern in function argument: `_` not covered
1414
f(4);
1515
}

0 commit comments

Comments
 (0)