Skip to content

Commit 9ba9cd5

Browse files
committed
Improve error message, fix and add tests.
Changes the non-exhaustive match error message to generate more general witnesses.
1 parent 9c5e86d commit 9ba9cd5

File tree

5 files changed

+131
-31
lines changed

5 files changed

+131
-31
lines changed

src/librustc_const_eval/_match.rs

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -359,25 +359,6 @@ impl<'tcx> Witness<'tcx> {
359359
}
360360
}
361361

362-
/// Return the set of constructors from the same type as the first column of `matrix`,
363-
/// that are matched only by wildcard patterns from that first column.
364-
///
365-
/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
366-
/// still be unmatched if the first constructor is replaced by any of the constructors
367-
/// in the return value.
368-
fn missing_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
369-
matrix: &Matrix,
370-
pcx: PatternContext<'tcx>) -> Vec<Constructor> {
371-
let used_constructors: Vec<Constructor> =
372-
matrix.0.iter()
373-
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
374-
.collect();
375-
debug!("used_constructors = {:?}", used_constructors);
376-
all_constructors(cx, pcx).into_iter()
377-
.filter(|c| !used_constructors.contains(c))
378-
.collect()
379-
}
380-
381362
/// This determines the set of all possible constructors of a pattern matching
382363
/// values of type `left_ty`. For vectors, this would normally be an infinite set
383364
///
@@ -586,10 +567,28 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
586567
).find(|result| result.is_useful()).unwrap_or(NotUseful)
587568
} else {
588569
debug!("is_useful - expanding wildcard");
589-
let constructors = missing_constructors(cx, matrix, pcx);
590-
debug!("is_useful - missing_constructors = {:?}", constructors);
591-
if constructors.is_empty() {
592-
all_constructors(cx, pcx).into_iter().map(|c| {
570+
571+
let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
572+
pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
573+
}).collect();
574+
debug!("used_ctors = {:?}", used_ctors);
575+
let all_ctors = all_constructors(cx, pcx);
576+
debug!("all_ctors = {:?}", all_ctors);
577+
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
578+
!used_ctors.contains(*c)
579+
}).cloned().collect();
580+
debug!("missing_ctors = {:?}", missing_ctors);
581+
582+
// `missing_ctors` is the set of constructors from the same type as the
583+
// first column of `matrix` that are matched only by wildcard patterns
584+
// from the first column.
585+
//
586+
// Therefore, if there is some pattern that is unmatched by `matrix`,
587+
// it will still be unmatched if the first constructor is replaced by
588+
// any of the constructors in `missing_ctors`
589+
590+
if missing_ctors.is_empty() {
591+
all_ctors.into_iter().map(|c| {
593592
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
594593
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
595594
} else {
@@ -603,11 +602,25 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
603602
match is_useful(cx, &matrix, &v[1..], witness) {
604603
UsefulWithWitness(pats) => {
605604
let cx = &*cx;
606-
UsefulWithWitness(pats.into_iter().flat_map(|witness| {
607-
constructors.iter().map(move |ctor| {
608-
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
609-
})
610-
}).collect())
605+
let new_witnesses = if used_ctors.is_empty() {
606+
// All constructors are unused. Add wild patterns
607+
// rather than each individual constructor
608+
pats.into_iter().map(|mut witness| {
609+
witness.0.push(P(hir::Pat {
610+
id: DUMMY_NODE_ID,
611+
node: PatKind::Wild,
612+
span: DUMMY_SP,
613+
}));
614+
witness
615+
}).collect()
616+
} else {
617+
pats.into_iter().flat_map(|witness| {
618+
missing_ctors.iter().map(move |ctor| {
619+
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
620+
})
621+
}).collect()
622+
};
623+
UsefulWithWitness(new_witnesses)
611624
}
612625
result => result
613626
}

src/test/compile-fail/match-slice-patterns.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
fn check(list: &[Option<()>]) {
1414
match list {
15-
//~^ ERROR `&[None, Some(_), None, _]` and `&[Some(_), Some(_), None, _]` not covered
15+
//~^ ERROR `&[_, Some(_), None, _]` not covered
1616
&[] => {},
1717
&[_] => {},
1818
&[_, _] => {},
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2012 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(never_type)]
12+
13+
mod foo {
14+
pub struct SecretlyEmpty {
15+
_priv: !,
16+
}
17+
18+
pub struct NotSoSecretlyEmpty {
19+
pub _pub: !,
20+
}
21+
}
22+
23+
struct NotSoSecretlyEmpty {
24+
_priv: !,
25+
}
26+
27+
enum Foo {
28+
A(foo::SecretlyEmpty),
29+
B(foo::NotSoSecretlyEmpty),
30+
C(NotSoSecretlyEmpty),
31+
D(u32),
32+
}
33+
34+
fn main() {
35+
let x: Foo = Foo::D(123);
36+
let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
37+
}
38+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2012 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(box_patterns)]
12+
#![feature(slice_patterns)]
13+
#![feature(box_syntax)]
14+
#![feature(never_type)]
15+
#![deny(unreachable_patterns)]
16+
17+
mod foo {
18+
pub struct SecretlyEmpty {
19+
_priv: !,
20+
}
21+
}
22+
23+
struct NotSoSecretlyEmpty {
24+
_priv: !,
25+
}
26+
27+
fn main() {
28+
let x: &[!] = &[];
29+
30+
match x {
31+
&[] => (),
32+
&[..] => (), //~ ERROR unreachable pattern
33+
};
34+
35+
let x: Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]> = Err(&[]);
36+
match x {
37+
Ok(box _) => (), //~ ERROR unreachable pattern
38+
Err(&[]) => (),
39+
Err(&[..]) => (), //~ ERROR unreachable pattern
40+
}
41+
42+
let x: Result<foo::SecretlyEmpty, Result<NotSoSecretlyEmpty, u32>> = Err(Err(123));
43+
match x {
44+
Ok(_y) => (),
45+
Err(Err(_y)) => (),
46+
Err(Ok(_y)) => (), //~ ERROR unreachable pattern
47+
}
48+
}
49+

src/test/ui/check_match/issue-35609.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more n
44
20 | match (A, ()) {
55
| ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
66

7-
error[E0004]: non-exhaustive patterns: `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
7+
error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
88
--> $DIR/issue-35609.rs:24:11
99
|
1010
24 | match (A, A) {
11-
| ^^^^^^ patterns `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
11+
| ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
1212

1313
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
1414
--> $DIR/issue-35609.rs:28:11

0 commit comments

Comments
 (0)