diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 6f94edb9932..d31b5f104e5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -385,6 +385,27 @@ impl<'tcx> Pat<'tcx> { pub(super) fn is_wildcard(&self) -> bool { matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) } + + fn is_or_pat(&self) -> bool { + matches!(*self.kind, PatKind::Or { .. }) + } + + /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. + fn expand_or_pat(&self) -> Vec<&Self> { + fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { + if let PatKind::Or { pats } = pat.kind.as_ref() { + for pat in pats { + expand(pat, vec); + } + } else { + vec.push(pat) + } + } + + let mut pats = Vec::new(); + expand(self, &mut pats); + pats + } } /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` @@ -425,23 +446,14 @@ fn iter(&self) -> impl Iterator> { self.pats.iter().copied() } - // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`. - fn expand_or_pat(&self) -> Option> { - 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.pats.extend_from_slice(&self.pats[1..]); - new_patstack - }) - .collect(), - ) - } else { - None - } + // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an + // or-pattern. Panics if `self` is empty. + fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { + self.head().expand_or_pat().into_iter().map(move |pat| { + let mut new_patstack = PatStack::from_pattern(pat); + new_patstack.pats.extend_from_slice(&self.pats[1..]); + new_patstack + }) } /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. @@ -508,13 +520,12 @@ pub(super) fn column_count(&self) -> Option { self.patterns.get(0).map(|r| r.len()) } - /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. + /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively + /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { - if let Some(rows) = row.expand_or_pat() { - for row in rows { - // We recursively expand the or-patterns of the new rows. - // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`. - self.push(row) + if !row.is_empty() && row.head().is_or_pat() { + for row in row.expand_or_pat() { + self.patterns.push(row); } } else { self.patterns.push(row); @@ -968,8 +979,9 @@ fn is_useful<'p, 'tcx>( let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; // If the first pattern is an or-pattern, expand it. - let ret = if let Some(vs) = v.expand_or_pat() { + let ret = if v.head().is_or_pat() { debug!("expanding or-pattern"); + let vs: Vec<_> = v.expand_or_pat().collect(); let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect(); // We expand the or pattern, trying each of its branches in turn and keeping careful track // of possible unreachable sub-branches. diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index f51ba683cab..9718396ed48 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -53,8 +53,11 @@ fn main() { _ => {} } match 0 { + // We get two errors because recursive or-pattern expansion means we don't notice the two + // errors span a whole pattern. This could be better but doesn't matter much 0 | (0 | 0) => {} //~^ ERROR unreachable + //~| ERROR unreachable _ => {} } match None { diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index f61e7f2281a..901a71885eb 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -83,71 +83,77 @@ LL | (0 | 1) | 1 => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:56:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:58:14 | LL | 0 | (0 | 0) => {} - | ^^^^^ + | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:63:13 + --> $DIR/exhaustiveness-unreachable-pattern.rs:58:18 + | +LL | 0 | (0 | 0) => {} + | ^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:66:13 | LL | / Some( LL | | 0 | 0) => {} | |______________________^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:69:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:72:15 | LL | | 0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:71:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:74:15 | LL | | 0] => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:79:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:82:10 | LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:91:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:94:10 | LL | [true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:98:36 + --> $DIR/exhaustiveness-unreachable-pattern.rs:101:36 | LL | (true | false, None | Some(true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:114:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:117:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:133:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:136:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:141:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:144:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:147:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:150:15 | LL | | true, | ^^^^ -error: aborting due to 24 previous errors +error: aborting due to 25 previous errors