Skip to content

Commit 0162d60

Browse files
committed
Factor or-pattern expansion
1 parent 293af41 commit 0162d60

File tree

3 files changed

+58
-37
lines changed

3 files changed

+58
-37
lines changed

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,27 @@ impl<'tcx> Pat<'tcx> {
385385
pub(super) fn is_wildcard(&self) -> bool {
386386
matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
387387
}
388+
389+
fn is_or_pat(&self) -> bool {
390+
matches!(*self.kind, PatKind::Or { .. })
391+
}
392+
393+
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
394+
fn expand_or_pat(&self) -> Vec<&Self> {
395+
fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
396+
if let PatKind::Or { pats } = pat.kind.as_ref() {
397+
for pat in pats {
398+
expand(pat, vec);
399+
}
400+
} else {
401+
vec.push(pat)
402+
}
403+
}
404+
405+
let mut pats = Vec::new();
406+
expand(self, &mut pats);
407+
pats
408+
}
388409
}
389410

390411
/// 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> {
425446
self.pats.iter().copied()
426447
}
427448

428-
// If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
429-
fn expand_or_pat(&self) -> Option<Vec<Self>> {
430-
if self.is_empty() {
431-
None
432-
} else if let PatKind::Or { pats } = &*self.head().kind {
433-
Some(
434-
pats.iter()
435-
.map(|pat| {
436-
let mut new_patstack = PatStack::from_pattern(pat);
437-
new_patstack.pats.extend_from_slice(&self.pats[1..]);
438-
new_patstack
439-
})
440-
.collect(),
441-
)
442-
} else {
443-
None
444-
}
449+
// Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
450+
// or-pattern. Panics if `self` is empty.
451+
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
452+
self.head().expand_or_pat().into_iter().map(move |pat| {
453+
let mut new_patstack = PatStack::from_pattern(pat);
454+
new_patstack.pats.extend_from_slice(&self.pats[1..]);
455+
new_patstack
456+
})
445457
}
446458

447459
/// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
@@ -508,13 +520,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
508520
self.patterns.get(0).map(|r| r.len())
509521
}
510522

511-
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
523+
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
524+
/// expands it.
512525
fn push(&mut self, row: PatStack<'p, 'tcx>) {
513-
if let Some(rows) = row.expand_or_pat() {
514-
for row in rows {
515-
// We recursively expand the or-patterns of the new rows.
516-
// This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
517-
self.push(row)
526+
if !row.is_empty() && row.head().is_or_pat() {
527+
for row in row.expand_or_pat() {
528+
self.patterns.push(row);
518529
}
519530
} else {
520531
self.patterns.push(row);
@@ -968,8 +979,9 @@ fn is_useful<'p, 'tcx>(
968979
let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
969980

970981
// If the first pattern is an or-pattern, expand it.
971-
let ret = if let Some(vs) = v.expand_or_pat() {
982+
let ret = if v.head().is_or_pat() {
972983
debug!("expanding or-pattern");
984+
let vs: Vec<_> = v.expand_or_pat().collect();
973985
let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect();
974986
// We expand the or pattern, trying each of its branches in turn and keeping careful track
975987
// of possible unreachable sub-branches.

src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ fn main() {
5353
_ => {}
5454
}
5555
match 0 {
56+
// We get two errors because recursive or-pattern expansion means we don't notice the two
57+
// errors span a whole pattern. This could be better but doesn't matter much
5658
0 | (0 | 0) => {}
5759
//~^ ERROR unreachable
60+
//~| ERROR unreachable
5861
_ => {}
5962
}
6063
match None {

src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,71 +83,77 @@ LL | (0 | 1) | 1 => {}
8383
| ^
8484

8585
error: unreachable pattern
86-
--> $DIR/exhaustiveness-unreachable-pattern.rs:56:14
86+
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
8787
|
8888
LL | 0 | (0 | 0) => {}
89-
| ^^^^^
89+
| ^
90+
91+
error: unreachable pattern
92+
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
93+
|
94+
LL | 0 | (0 | 0) => {}
95+
| ^
9096

9197
error: unreachable pattern
92-
--> $DIR/exhaustiveness-unreachable-pattern.rs:63:13
98+
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
9399
|
94100
LL | / Some(
95101
LL | | 0 | 0) => {}
96102
| |______________________^
97103

98104
error: unreachable pattern
99-
--> $DIR/exhaustiveness-unreachable-pattern.rs:69:15
105+
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
100106
|
101107
LL | | 0
102108
| ^
103109

104110
error: unreachable pattern
105-
--> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
111+
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
106112
|
107113
LL | | 0] => {}
108114
| ^
109115

110116
error: unreachable pattern
111-
--> $DIR/exhaustiveness-unreachable-pattern.rs:79:10
117+
--> $DIR/exhaustiveness-unreachable-pattern.rs:82:10
112118
|
113119
LL | [1
114120
| ^
115121

116122
error: unreachable pattern
117-
--> $DIR/exhaustiveness-unreachable-pattern.rs:91:10
123+
--> $DIR/exhaustiveness-unreachable-pattern.rs:94:10
118124
|
119125
LL | [true
120126
| ^^^^
121127

122128
error: unreachable pattern
123-
--> $DIR/exhaustiveness-unreachable-pattern.rs:98:36
129+
--> $DIR/exhaustiveness-unreachable-pattern.rs:101:36
124130
|
125131
LL | (true | false, None | Some(true
126132
| ^^^^
127133

128134
error: unreachable pattern
129-
--> $DIR/exhaustiveness-unreachable-pattern.rs:114:14
135+
--> $DIR/exhaustiveness-unreachable-pattern.rs:117:14
130136
|
131137
LL | Some(0
132138
| ^
133139

134140
error: unreachable pattern
135-
--> $DIR/exhaustiveness-unreachable-pattern.rs:133:19
141+
--> $DIR/exhaustiveness-unreachable-pattern.rs:136:19
136142
|
137143
LL | | false) => {}
138144
| ^^^^^
139145

140146
error: unreachable pattern
141-
--> $DIR/exhaustiveness-unreachable-pattern.rs:141:15
147+
--> $DIR/exhaustiveness-unreachable-pattern.rs:144:15
142148
|
143149
LL | | true) => {}
144150
| ^^^^
145151

146152
error: unreachable pattern
147-
--> $DIR/exhaustiveness-unreachable-pattern.rs:147:15
153+
--> $DIR/exhaustiveness-unreachable-pattern.rs:150:15
148154
|
149155
LL | | true,
150156
| ^^^^
151157

152-
error: aborting due to 24 previous errors
158+
error: aborting due to 25 previous errors
153159

0 commit comments

Comments
 (0)