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::AscribeUserType { .. } |
|
||||||
PatKind::Array { .. } |
|
PatKind::Array { .. } |
|
||||||
PatKind::Wild |
|
PatKind::Wild |
|
||||||
PatKind::Or { .. } |
|
|
||||||
PatKind::Binding { .. } |
|
PatKind::Binding { .. } |
|
||||||
PatKind::Leaf { .. } |
|
PatKind::Leaf { .. } |
|
||||||
PatKind::Deref { .. } => {
|
PatKind::Deref { .. } => {
|
||||||
|
@ -400,6 +400,25 @@ fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
|
|||||||
self.0.iter().map(|p| *p)
|
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.
|
/// This computes `D(self)`. See top of the file for explanations.
|
||||||
fn specialize_wildcard(&self) -> Option<Self> {
|
fn specialize_wildcard(&self) -> Option<Self> {
|
||||||
if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
|
if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
|
||||||
@ -447,8 +466,13 @@ pub fn empty() -> Self {
|
|||||||
Matrix(vec![])
|
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>) {
|
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
|
/// Iterate over the first component of each row
|
||||||
@ -472,12 +496,10 @@ fn specialize_constructor<'a, 'q>(
|
|||||||
'a: 'q,
|
'a: 'q,
|
||||||
'p: 'q,
|
'p: 'q,
|
||||||
{
|
{
|
||||||
Matrix(
|
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
|
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
|
||||||
.collect(),
|
.collect()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +551,12 @@ fn from_iter<T>(iter: T) -> Self
|
|||||||
where
|
where
|
||||||
T: IntoIterator<Item = PatStack<'p, 'tcx>>,
|
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()));
|
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
|
let (ty, span) = matrix
|
||||||
.heads()
|
.heads()
|
||||||
.map(|r| (r.ty, r.span))
|
.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) };
|
if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
|
||||||
Some(Slice(Slice { array_len, kind }))
|
Some(Slice(Slice { array_len, kind }))
|
||||||
}
|
}
|
||||||
PatKind::Or { .. } => {
|
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
|
||||||
bug!("support for or-patterns has not been fully implemented yet.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2404,9 +2438,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
|
|||||||
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
|
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
|
||||||
},
|
},
|
||||||
|
|
||||||
PatKind::Or { .. } => {
|
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
|
||||||
bug!("support for or-patterns has not been fully implemented yet.");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
|
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