Skip to content

Commit

Permalink
Rollup merge of rust-lang#66612 - Nadrieril:or-patterns-initial, r=va…
Browse files Browse the repository at this point in the history
…rkor

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 rust-lang#54883
  • Loading branch information
Centril authored Nov 30, 2019
2 parents d8bdb3f + 0f4c5fb commit 3af14f9
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 15 deletions.
8 changes: 7 additions & 1 deletion src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,16 @@ impl<'a, 'tcx> Builder<'a, '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 { .. } => {
Expand Down
60 changes: 46 additions & 14 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,25 @@ impl<'p, 'tcx> PatStack<'p, '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 }
Expand Down Expand Up @@ -447,8 +466,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
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
Expand All @@ -472,12 +496,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
'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()
}
}

Expand Down Expand Up @@ -529,7 +551,12 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
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
}
}

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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."),
}
}

Expand Down Expand Up @@ -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);

Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
Original file line number Diff line number Diff line change
@@ -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),) => {}
}
}
33 changes: 33 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
Original file line number Diff line number Diff line change
@@ -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`.
40 changes: 40 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-pass.rs
Original file line number Diff line number Diff line change
@@ -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] | [_, ..],) => {},
}
}
8 changes: 8 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-pass.stderr
Original file line number Diff line number Diff line change
@@ -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

51 changes: 51 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
Original file line number Diff line number Diff line change
@@ -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
_ => {},
}
}
80 changes: 80 additions & 0 deletions src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3af14f9

Please sign in to comment.