Factor or-pattern expansion

This commit is contained in:
Nadrieril 2021-01-01 22:14:22 +00:00
parent 293af41790
commit 0162d603b3
3 changed files with 58 additions and 37 deletions

View File

@ -385,6 +385,27 @@ impl<'tcx> Pat<'tcx> {
pub(super) fn is_wildcard(&self) -> bool { pub(super) fn is_wildcard(&self) -> bool {
matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) 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]` /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
@ -425,23 +446,14 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
self.pats.iter().copied() self.pats.iter().copied()
} }
// If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`. // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
fn expand_or_pat(&self) -> Option<Vec<Self>> { // or-pattern. Panics if `self` is empty.
if self.is_empty() { fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
None self.head().expand_or_pat().into_iter().map(move |pat| {
} else if let PatKind::Or { pats } = &*self.head().kind { let mut new_patstack = PatStack::from_pattern(pat);
Some( new_patstack.pats.extend_from_slice(&self.pats[1..]);
pats.iter() new_patstack
.map(|pat| { })
let mut new_patstack = PatStack::from_pattern(pat);
new_patstack.pats.extend_from_slice(&self.pats[1..]);
new_patstack
})
.collect(),
)
} else {
None
}
} }
/// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
@ -508,13 +520,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
self.patterns.get(0).map(|r| r.len()) 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>) { fn push(&mut self, row: PatStack<'p, 'tcx>) {
if let Some(rows) = row.expand_or_pat() { if !row.is_empty() && row.head().is_or_pat() {
for row in rows { for row in row.expand_or_pat() {
// We recursively expand the or-patterns of the new rows. self.patterns.push(row);
// This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
self.push(row)
} }
} else { } else {
self.patterns.push(row); 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 }; let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
// If the first pattern is an or-pattern, expand it. // 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"); debug!("expanding or-pattern");
let vs: Vec<_> = v.expand_or_pat().collect();
let subspans: Vec<_> = vs.iter().map(|v| v.head().span).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 // We expand the or pattern, trying each of its branches in turn and keeping careful track
// of possible unreachable sub-branches. // of possible unreachable sub-branches.

View File

@ -53,8 +53,11 @@ fn main() {
_ => {} _ => {}
} }
match 0 { 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) => {} 0 | (0 | 0) => {}
//~^ ERROR unreachable //~^ ERROR unreachable
//~| ERROR unreachable
_ => {} _ => {}
} }
match None { match None {

View File

@ -83,71 +83,77 @@ LL | (0 | 1) | 1 => {}
| ^ | ^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:56:14 --> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
| |
LL | 0 | (0 | 0) => {} LL | 0 | (0 | 0) => {}
| ^^^^^ | ^
error: unreachable pattern 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 | / Some(
LL | | 0 | 0) => {} LL | | 0 | 0) => {}
| |______________________^ | |______________________^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:69:15 --> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
| |
LL | | 0 LL | | 0
| ^ | ^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:71:15 --> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
| |
LL | | 0] => {} LL | | 0] => {}
| ^ | ^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:79:10 --> $DIR/exhaustiveness-unreachable-pattern.rs:82:10
| |
LL | [1 LL | [1
| ^ | ^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:91:10 --> $DIR/exhaustiveness-unreachable-pattern.rs:94:10
| |
LL | [true LL | [true
| ^^^^ | ^^^^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:98:36 --> $DIR/exhaustiveness-unreachable-pattern.rs:101:36
| |
LL | (true | false, None | Some(true LL | (true | false, None | Some(true
| ^^^^ | ^^^^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:114:14 --> $DIR/exhaustiveness-unreachable-pattern.rs:117:14
| |
LL | Some(0 LL | Some(0
| ^ | ^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:133:19 --> $DIR/exhaustiveness-unreachable-pattern.rs:136:19
| |
LL | | false) => {} LL | | false) => {}
| ^^^^^ | ^^^^^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:141:15 --> $DIR/exhaustiveness-unreachable-pattern.rs:144:15
| |
LL | | true) => {} LL | | true) => {}
| ^^^^ | ^^^^
error: unreachable pattern error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:147:15 --> $DIR/exhaustiveness-unreachable-pattern.rs:150:15
| |
LL | | true, LL | | true,
| ^^^^ | ^^^^
error: aborting due to 24 previous errors error: aborting due to 25 previous errors