Improve error message, fix and add tests.

Changes the non-exhaustive match error message to generate more general
witnesses.
This commit is contained in:
Andrew Cann 2016-12-01 11:37:03 +08:00
parent 9c5e86d0cd
commit 9ba9cd5fd5
5 changed files with 131 additions and 31 deletions

View file

@ -359,25 +359,6 @@ impl<'tcx> Witness<'tcx> {
}
}
/// Return the set of constructors from the same type as the first column of `matrix`,
/// that are matched only by wildcard patterns from that first column.
///
/// Therefore, if there is some pattern that is unmatched by `matrix`, it will
/// still be unmatched if the first constructor is replaced by any of the constructors
/// in the return value.
fn missing_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix,
pcx: PatternContext<'tcx>) -> Vec<Constructor> {
let used_constructors: Vec<Constructor> =
matrix.0.iter()
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
.collect();
debug!("used_constructors = {:?}", used_constructors);
all_constructors(cx, pcx).into_iter()
.filter(|c| !used_constructors.contains(c))
.collect()
}
/// This determines the set of all possible constructors of a pattern matching
/// values of type `left_ty`. For vectors, this would normally be an infinite set
///
@ -586,10 +567,28 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
debug!("is_useful - expanding wildcard");
let constructors = missing_constructors(cx, matrix, pcx);
debug!("is_useful - missing_constructors = {:?}", constructors);
if constructors.is_empty() {
all_constructors(cx, pcx).into_iter().map(|c| {
let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
}).collect();
debug!("used_ctors = {:?}", used_ctors);
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:?}", all_ctors);
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
!used_ctors.contains(*c)
}).cloned().collect();
debug!("missing_ctors = {:?}", missing_ctors);
// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
// from the first column.
//
// Therefore, if there is some pattern that is unmatched by `matrix`,
// it will still be unmatched if the first constructor is replaced by
// any of the constructors in `missing_ctors`
if missing_ctors.is_empty() {
all_ctors.into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
@ -603,11 +602,25 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
match is_useful(cx, &matrix, &v[1..], witness) {
UsefulWithWitness(pats) => {
let cx = &*cx;
UsefulWithWitness(pats.into_iter().flat_map(|witness| {
constructors.iter().map(move |ctor| {
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
})
}).collect())
let new_witnesses = if used_ctors.is_empty() {
// All constructors are unused. Add wild patterns
// rather than each individual constructor
pats.into_iter().map(|mut witness| {
witness.0.push(P(hir::Pat {
id: DUMMY_NODE_ID,
node: PatKind::Wild,
span: DUMMY_SP,
}));
witness
}).collect()
} else {
pats.into_iter().flat_map(|witness| {
missing_ctors.iter().map(move |ctor| {
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
})
}).collect()
};
UsefulWithWitness(new_witnesses)
}
result => result
}

View file

@ -12,7 +12,7 @@
fn check(list: &[Option<()>]) {
match list {
//~^ ERROR `&[None, Some(_), None, _]` and `&[Some(_), Some(_), None, _]` not covered
//~^ ERROR `&[_, Some(_), None, _]` not covered
&[] => {},
&[_] => {},
&[_, _] => {},

View file

@ -0,0 +1,38 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(never_type)]
mod foo {
pub struct SecretlyEmpty {
_priv: !,
}
pub struct NotSoSecretlyEmpty {
pub _pub: !,
}
}
struct NotSoSecretlyEmpty {
_priv: !,
}
enum Foo {
A(foo::SecretlyEmpty),
B(foo::NotSoSecretlyEmpty),
C(NotSoSecretlyEmpty),
D(u32),
}
fn main() {
let x: Foo = Foo::D(123);
let Foo::D(_y) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
}

View file

@ -0,0 +1,49 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_patterns)]
#![feature(slice_patterns)]
#![feature(box_syntax)]
#![feature(never_type)]
#![deny(unreachable_patterns)]
mod foo {
pub struct SecretlyEmpty {
_priv: !,
}
}
struct NotSoSecretlyEmpty {
_priv: !,
}
fn main() {
let x: &[!] = &[];
match x {
&[] => (),
&[..] => (), //~ ERROR unreachable pattern
};
let x: Result<Box<NotSoSecretlyEmpty>, &[Result<!, !>]> = Err(&[]);
match x {
Ok(box _) => (), //~ ERROR unreachable pattern
Err(&[]) => (),
Err(&[..]) => (), //~ ERROR unreachable pattern
}
let x: Result<foo::SecretlyEmpty, Result<NotSoSecretlyEmpty, u32>> = Err(Err(123));
match x {
Ok(_y) => (),
Err(Err(_y)) => (),
Err(Ok(_y)) => (), //~ ERROR unreachable pattern
}
}

View file

@ -4,11 +4,11 @@ error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more n
20 | match (A, ()) {
| ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
error[E0004]: non-exhaustive patterns: `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
--> $DIR/issue-35609.rs:24:11
|
24 | match (A, A) {
| ^^^^^^ patterns `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
| ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:28:11