Rollup merge of #66612 - Nadrieril:or-patterns-initial, r=varkor

Initial implementation of or-pattern usefulness checking

The title says it all.
I'd like to request a perf run on that, hopefully this doesn't kill performance too much.

cc https://github.com/rust-lang/rust/issues/54883
This commit is contained in:
Mazdak Farrokhzad 2019-11-30 16:56:45 +01:00 committed by GitHub
commit 3af14f994d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 291 additions and 15 deletions

View File

@ -84,10 +84,16 @@ pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
}
}
PatKind::Or { .. } => {
self.hir.tcx().sess.span_fatal(
match_pair.pattern.span,
"or-patterns are not fully implemented yet"
)
}
PatKind::AscribeUserType { .. } |
PatKind::Array { .. } |
PatKind::Wild |
PatKind::Or { .. } |
PatKind::Binding { .. } |
PatKind::Leaf { .. } |
PatKind::Deref { .. } => {

View File

@ -400,6 +400,25 @@ fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
self.0.iter().map(|p| *p)
}
// If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
fn expand_or_pat(&self) -> Option<Vec<Self>> {
if self.is_empty() {
None
} else if let PatKind::Or { pats } = &*self.head().kind {
Some(
pats.iter()
.map(|pat| {
let mut new_patstack = PatStack::from_pattern(pat);
new_patstack.0.extend_from_slice(&self.0[1..]);
new_patstack
})
.collect(),
)
} else {
None
}
}
/// This computes `D(self)`. See top of the file for explanations.
fn specialize_wildcard(&self) -> Option<Self> {
if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
@ -447,8 +466,13 @@ pub fn empty() -> Self {
Matrix(vec![])
}
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
self.0.push(row)
if let Some(rows) = row.expand_or_pat() {
self.0.extend(rows);
} else {
self.0.push(row);
}
}
/// Iterate over the first component of each row
@ -472,12 +496,10 @@ fn specialize_constructor<'a, 'q>(
'a: 'q,
'p: 'q,
{
Matrix(
self.0
.iter()
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
.collect(),
)
self.0
.iter()
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
.collect()
}
}
@ -529,7 +551,12 @@ fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = PatStack<'p, 'tcx>>,
{
Matrix(iter.into_iter().collect())
let mut matrix = Matrix::empty();
for x in iter {
// Using `push` ensures we correctly expand or-patterns.
matrix.push(x);
}
matrix
}
}
@ -1602,6 +1629,15 @@ pub fn is_useful<'p, 'a, 'tcx>(
assert!(rows.iter().all(|r| r.len() == v.len()));
// If the first pattern is an or-pattern, expand it.
if let Some(vs) = v.expand_or_pat() {
return vs
.into_iter()
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful);
}
let (ty, span) = matrix
.heads()
.map(|r| (r.ty, r.span))
@ -1813,9 +1849,7 @@ fn pat_constructor<'tcx>(
if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
Some(Slice(Slice { array_len, kind }))
}
PatKind::Or { .. } => {
bug!("support for or-patterns has not been fully implemented yet.");
}
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
}
}
@ -2404,9 +2438,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
},
PatKind::Or { .. } => {
bug!("support for or-patterns has not been fully implemented yet.");
}
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
};
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);

View File

@ -0,0 +1,26 @@
#![feature(or_patterns)]
#![feature(slice_patterns)]
#![allow(incomplete_features)]
#![deny(unreachable_patterns)]
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
fn main() {
// Get the fatal error out of the way
match (0u8,) {
(0 | _,) => {}
//~^ ERROR or-patterns are not fully implemented yet
}
match (0u8, 0u8) {
//~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)`
(0 | 1, 2 | 3) => {}
}
match ((0u8,),) {
//~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))`
((0 | 1,) | (2 | 3,),) => {},
}
match (Some(0u8),) {
//~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))`
(None | Some(0 | 1),) => {}
}
}

View File

@ -0,0 +1,33 @@
error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:14:11
|
LL | match (0u8, 0u8) {
| ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:18:11
|
LL | match ((0u8,),) {
| ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:22:11
|
LL | match (Some(0u8),) {
| ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
error: or-patterns are not fully implemented yet
--> $DIR/exhaustiveness-non-exhaustive.rs:10:10
|
LL | (0 | _,) => {}
| ^^^^^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0004`.

View File

@ -0,0 +1,40 @@
#![feature(or_patterns)]
#![feature(slice_patterns)]
#![allow(incomplete_features)]
#![deny(unreachable_patterns)]
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
fn main() {
// Get the fatal error out of the way
match (0u8,) {
(0 | _,) => {}
//~^ ERROR or-patterns are not fully implemented yet
}
match (0u8,) {
(1 | 2,) => {}
_ => {}
}
match (0u8,) {
(1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
_ => {}
}
match (0u8, 0u8) {
(1 | 2, 3 | 4) => {}
(1, 2) => {}
(2, 1) => {}
_ => {}
}
match (Some(0u8),) {
(None | Some(0 | 1),) => {}
(Some(2..=255),) => {}
}
match ((0u8,),) {
((0 | 1,) | (2 | 3,),) => {},
((_,),) => {},
}
match (&[0u8][..],) {
([] | [0 | 1..=255] | [_, ..],) => {},
}
}

View File

@ -0,0 +1,8 @@
error: or-patterns are not fully implemented yet
--> $DIR/exhaustiveness-pass.rs:10:10
|
LL | (0 | _,) => {}
| ^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,51 @@
#![feature(or_patterns)]
#![feature(slice_patterns)]
#![allow(incomplete_features)]
#![deny(unreachable_patterns)]
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
fn main() {
// Get the fatal error out of the way
match (0u8,) {
(0 | _,) => {}
//~^ ERROR or-patterns are not fully implemented yet
}
match (0u8,) {
(1 | 2,) => {}
(1,) => {} //~ ERROR unreachable pattern
_ => {}
}
match (0u8,) {
(1 | 2,) => {}
(2,) => {} //~ ERROR unreachable pattern
_ => {}
}
match (0u8,) {
(1,) => {}
(2,) => {}
(1 | 2,) => {} //~ ERROR unreachable pattern
_ => {}
}
match (0u8, 0u8) {
(1 | 2, 3 | 4) => {}
(1, 3) => {} //~ ERROR unreachable pattern
(1, 4) => {} //~ ERROR unreachable pattern
(2, 4) => {} //~ ERROR unreachable pattern
(2 | 1, 4) => {} //~ ERROR unreachable pattern
(1, 5 | 6) => {}
(1, 4 | 5) => {} //~ ERROR unreachable pattern
_ => {}
}
match (Some(0u8),) {
(None | Some(1 | 2),) => {}
(Some(1),) => {} //~ ERROR unreachable pattern
(None,) => {} //~ ERROR unreachable pattern
_ => {}
}
match ((0u8,),) {
((1 | 2,) | (3 | 4,),) => {},
((1..=4,),) => {}, //~ ERROR unreachable pattern
_ => {},
}
}

View File

@ -0,0 +1,80 @@
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:16:9
|
LL | (1,) => {}
| ^^^^
|
note: lint level defined here
--> $DIR/exhaustiveness-unreachable-pattern.rs:4:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:21:9
|
LL | (2,) => {}
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
|
LL | (1 | 2,) => {}
| ^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:32:9
|
LL | (1, 3) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:33:9
|
LL | (1, 4) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:34:9
|
LL | (2, 4) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:35:9
|
LL | (2 | 1, 4) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
|
LL | (1, 4 | 5) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
|
LL | (Some(1),) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
|
LL | (None,) => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
|
LL | ((1..=4,),) => {},
| ^^^^^^^^^^^
error: or-patterns are not fully implemented yet
--> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
|
LL | (0 | _,) => {}
| ^^^^^
error: aborting due to 12 previous errors