diff options
Diffstat (limited to 'src')
8 files changed, 291 insertions, 15 deletions
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 07c5d640a32..c893d6f4856 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -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 { .. } => { diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 5db567dae29..f2c5bf1bf6d 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -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 } @@ -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 @@ -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() } } @@ -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 } } @@ -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); diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs new file mode 100644 index 00000000000..d7c191bb5a2 --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs @@ -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),) => {} + } +} diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr new file mode 100644 index 00000000000..e6aa157d278 --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -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`. diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.rs b/src/test/ui/or-patterns/exhaustiveness-pass.rs new file mode 100644 index 00000000000..62a851719f9 --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-pass.rs @@ -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] | [_, ..],) => {}, + } +} diff --git a/src/test/ui/or-patterns/exhaustiveness-pass.stderr b/src/test/ui/or-patterns/exhaustiveness-pass.stderr new file mode 100644 index 00000000000..1f4278c4b80 --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-pass.stderr @@ -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 + diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs new file mode 100644 index 00000000000..2cd8ca2dbac --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -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 + _ => {}, + } +} diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr new file mode 100644 index 00000000000..a4d55d805c3 --- /dev/null +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -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 + |
