Skip to content

Commit

Permalink
Initial implementation of or-pattern usefulness checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Nov 21, 2019
1 parent f1b882b commit 6e85f46
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 14 deletions.
60 changes: 46 additions & 14 deletions src/librustc_mir/hair/pattern/_match.rs
Expand Up @@ -399,6 +399,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<PatStack<'p, 'tcx>>> {
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 @@ -446,8 +465,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 @@ -471,12 +495,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 @@ -528,7 +550,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 @@ -1601,6 +1628,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 @@ -1802,9 +1838,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!(), // Should have been expanded earlier on.
}
}

Expand Down Expand Up @@ -2410,9 +2444,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!(), // Should have been expanded earlier on.
};
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);

Expand Down
45 changes: 45 additions & 0 deletions src/test/compile-fail/or-patterns.rs
@@ -0,0 +1,45 @@
// should-ice
#![allow(incomplete_features)]
#![feature(or_patterns)]
#![deny(unreachable_patterns)]

// The ice will get removed once or-patterns are correctly implemented
fn main() {
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
match (0u8,) {
(1 | 2,) => {}
//~^ ERROR simplifyable pattern found
// This above is the ICE error message
_ => {}
}

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,) {
(1 | 1,) => {} // redundancy not detected for now
_ => {}
}
match (0u8, 0u8) {
(1 | 2, 3 | 4) => {}
(1, 2) => {}
(1, 3) => {} //~ ERROR unreachable pattern
(1, 4) => {} //~ ERROR unreachable pattern
(2, 4) => {} //~ ERROR unreachable pattern
(2 | 1, 4) => {} //~ ERROR unreachable pattern
_ => {}
}
}

0 comments on commit 6e85f46

Please sign in to comment.