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:
commit
3af14f994d
@ -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 { .. } => {
|
||||
|
@ -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);
|
||||
|
||||
|
26
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
Normal file
26
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
Normal 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),) => {}
|
||||
}
|
||||
}
|
33
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
Normal file
33
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
Normal 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`.
|
40
src/test/ui/or-patterns/exhaustiveness-pass.rs
Normal file
40
src/test/ui/or-patterns/exhaustiveness-pass.rs
Normal 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] | [_, ..],) => {},
|
||||
}
|
||||
}
|
8
src/test/ui/or-patterns/exhaustiveness-pass.stderr
Normal file
8
src/test/ui/or-patterns/exhaustiveness-pass.stderr
Normal 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
|
||||
|
@ -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
|
||||
_ => {},
|
||||
}
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user