diff options
| author | Nadrieril <nadrieril+git@gmail.com> | 2019-11-21 18:45:28 +0000 |
|---|---|---|
| committer | Nadrieril <nadrieril+git@gmail.com> | 2019-11-21 18:45:28 +0000 |
| commit | 6e85f467c59e7ae943404a2aee9cc83ee475cf23 (patch) | |
| tree | 50f7fda155477b593c16ed3b8976b690f2b3c154 | |
| parent | f1b882b55805c342e46ee4ca3beeef1d1fa2044b (diff) | |
| download | rust-6e85f467c59e7ae943404a2aee9cc83ee475cf23.tar.gz rust-6e85f467c59e7ae943404a2aee9cc83ee475cf23.zip | |
Initial implementation of or-pattern usefulness checking
| -rw-r--r-- | src/librustc_mir/hair/pattern/_match.rs | 60 | ||||
| -rw-r--r-- | src/test/compile-fail/or-patterns.rs | 45 |
2 files changed, 91 insertions, 14 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 5e7a7f01e7a..7d3bbbc1ee4 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -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 } @@ -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 @@ -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() } } @@ -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 } } @@ -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)) @@ -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. } } @@ -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); diff --git a/src/test/compile-fail/or-patterns.rs b/src/test/compile-fail/or-patterns.rs new file mode 100644 index 00000000000..e1b5dce852d --- /dev/null +++ b/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 + _ => {} + } +} |
