Skip to content

Commit 320df38

Browse files
committed
Auto merge of #66612 - Nadrieril:or-patterns-initial, r=<try>
Initial implementation of or-pattern usefulness checking The title says it all. I'd like to request a perf run on that, hopefully this doesn't kill performance too much. cc #54883
2 parents 5fa0af2 + 0030a77 commit 320df38

File tree

2 files changed

+102
-14
lines changed

2 files changed

+102
-14
lines changed

src/librustc_mir/hair/pattern/_match.rs

+46-14
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,25 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
399399
self.0.iter().map(|p| *p)
400400
}
401401

402+
// If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
403+
fn expand_or_pat(&self) -> Option<Vec<PatStack<'p, 'tcx>>> {
404+
if self.is_empty() {
405+
None
406+
} else if let PatKind::Or { pats } = &*self.head().kind {
407+
Some(
408+
pats.iter()
409+
.map(|pat| {
410+
let mut new_patstack = PatStack::from_pattern(pat);
411+
new_patstack.0.extend_from_slice(&self.0[1..]);
412+
new_patstack
413+
})
414+
.collect(),
415+
)
416+
} else {
417+
None
418+
}
419+
}
420+
402421
/// This computes `D(self)`. See top of the file for explanations.
403422
fn specialize_wildcard(&self) -> Option<Self> {
404423
if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
@@ -446,8 +465,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
446465
Matrix(vec![])
447466
}
448467

468+
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
449469
pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
450-
self.0.push(row)
470+
if let Some(rows) = row.expand_or_pat() {
471+
self.0.extend(rows);
472+
} else {
473+
self.0.push(row);
474+
}
451475
}
452476

453477
/// Iterate over the first component of each row
@@ -471,12 +495,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
471495
'a: 'q,
472496
'p: 'q,
473497
{
474-
Matrix(
475-
self.0
476-
.iter()
477-
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
478-
.collect(),
479-
)
498+
self.0
499+
.iter()
500+
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
501+
.collect()
480502
}
481503
}
482504

@@ -528,7 +550,12 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
528550
where
529551
T: IntoIterator<Item = PatStack<'p, 'tcx>>,
530552
{
531-
Matrix(iter.into_iter().collect())
553+
let mut matrix = Matrix::empty();
554+
for x in iter {
555+
// Using `push` ensures we correctly expand or-patterns.
556+
matrix.push(x);
557+
}
558+
matrix
532559
}
533560
}
534561

@@ -1601,6 +1628,15 @@ pub fn is_useful<'p, 'a, 'tcx>(
16011628

16021629
assert!(rows.iter().all(|r| r.len() == v.len()));
16031630

1631+
// If the first pattern is an or-pattern, expand it.
1632+
if let Some(vs) = v.expand_or_pat() {
1633+
return vs
1634+
.into_iter()
1635+
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
1636+
.find(|result| result.is_useful())
1637+
.unwrap_or(NotUseful);
1638+
}
1639+
16041640
let (ty, span) = matrix
16051641
.heads()
16061642
.map(|r| (r.ty, r.span))
@@ -1802,9 +1838,7 @@ fn pat_constructor<'tcx>(
18021838
if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
18031839
Some(Slice(Slice { array_len, kind }))
18041840
}
1805-
PatKind::Or { .. } => {
1806-
bug!("support for or-patterns has not been fully implemented yet.");
1807-
}
1841+
PatKind::Or { .. } => bug!(), // Should have been expanded earlier on.
18081842
}
18091843
}
18101844

@@ -2410,9 +2444,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
24102444
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
24112445
},
24122446

2413-
PatKind::Or { .. } => {
2414-
bug!("support for or-patterns has not been fully implemented yet.");
2415-
}
2447+
PatKind::Or { .. } => bug!(), // Should have been expanded earlier on.
24162448
};
24172449
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
24182450

src/test/compile-fail/or-patterns.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// should-ice
2+
#![allow(incomplete_features)]
3+
#![feature(or_patterns)]
4+
#![deny(unreachable_patterns)]
5+
6+
// The ice will get removed once or-patterns are correctly implemented
7+
fn main() {
8+
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
9+
match (0u8,) {
10+
(1 | 2,) => {}
11+
//~^ ERROR simplifyable pattern found
12+
// This above is the ICE error message
13+
_ => {}
14+
}
15+
16+
match (0u8,) {
17+
(1 | 2,) => {}
18+
(1,) => {} //~ ERROR unreachable pattern
19+
_ => {}
20+
}
21+
match (0u8,) {
22+
(1 | 2,) => {}
23+
(2,) => {} //~ ERROR unreachable pattern
24+
_ => {}
25+
}
26+
match (0u8,) {
27+
(1,) => {}
28+
(2,) => {}
29+
(1 | 2,) => {} //~ ERROR unreachable pattern
30+
_ => {}
31+
}
32+
match (0u8,) {
33+
(1 | 1,) => {} // redundancy not detected for now
34+
_ => {}
35+
}
36+
match (0u8, 0u8) {
37+
(1 | 2, 3 | 4) => {}
38+
(1, 2) => {}
39+
(1, 3) => {} //~ ERROR unreachable pattern
40+
(1, 4) => {} //~ ERROR unreachable pattern
41+
(2, 4) => {} //~ ERROR unreachable pattern
42+
(2 | 1, 4) => {} //~ ERROR unreachable pattern
43+
_ => {}
44+
}
45+
match (Some(0u8),) {
46+
(None | Some(1 | 2),) => {}
47+
(Some(1),) => {} //~ ERROR unreachable pattern
48+
(None,) => {} //~ ERROR unreachable pattern
49+
(Some(_),) => {}
50+
}
51+
match ((0u8,),) {
52+
((1 | 2,) | (3 | 4,),) => {},
53+
((1..=4,),) => {}, //~ ERROR unreachable pattern
54+
((_,),) => {},
55+
}
56+
}

0 commit comments

Comments
 (0)