Skip to content

Commit 3af14f9

Browse files
authored
Rollup merge of rust-lang#66612 - Nadrieril:or-patterns-initial, r=varkor
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 rust-lang#54883
2 parents d8bdb3f + 0f4c5fb commit 3af14f9

8 files changed

+291
-15
lines changed

src/librustc_mir/build/matches/test.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8484
}
8585
}
8686

87+
PatKind::Or { .. } => {
88+
self.hir.tcx().sess.span_fatal(
89+
match_pair.pattern.span,
90+
"or-patterns are not fully implemented yet"
91+
)
92+
}
93+
8794
PatKind::AscribeUserType { .. } |
8895
PatKind::Array { .. } |
8996
PatKind::Wild |
90-
PatKind::Or { .. } |
9197
PatKind::Binding { .. } |
9298
PatKind::Leaf { .. } |
9399
PatKind::Deref { .. } => {

src/librustc_mir/hair/pattern/_match.rs

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

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

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

454478
/// Iterate over the first component of each row
@@ -472,12 +496,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
472496
'a: 'q,
473497
'p: 'q,
474498
{
475-
Matrix(
476-
self.0
477-
.iter()
478-
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
479-
.collect(),
480-
)
499+
self.0
500+
.iter()
501+
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
502+
.collect()
481503
}
482504
}
483505

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

@@ -1602,6 +1629,15 @@ pub fn is_useful<'p, 'a, 'tcx>(
16021629

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

1632+
// If the first pattern is an or-pattern, expand it.
1633+
if let Some(vs) = v.expand_or_pat() {
1634+
return vs
1635+
.into_iter()
1636+
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
1637+
.find(|result| result.is_useful())
1638+
.unwrap_or(NotUseful);
1639+
}
1640+
16051641
let (ty, span) = matrix
16061642
.heads()
16071643
.map(|r| (r.ty, r.span))
@@ -1813,9 +1849,7 @@ fn pat_constructor<'tcx>(
18131849
if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
18141850
Some(Slice(Slice { array_len, kind }))
18151851
}
1816-
PatKind::Or { .. } => {
1817-
bug!("support for or-patterns has not been fully implemented yet.");
1818-
}
1852+
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
18191853
}
18201854
}
18211855

@@ -2404,9 +2438,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
24042438
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
24052439
},
24062440

2407-
PatKind::Or { .. } => {
2408-
bug!("support for or-patterns has not been fully implemented yet.");
2409-
}
2441+
PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
24102442
};
24112443
debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
24122444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(or_patterns)]
2+
#![feature(slice_patterns)]
3+
#![allow(incomplete_features)]
4+
#![deny(unreachable_patterns)]
5+
6+
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
7+
fn main() {
8+
// Get the fatal error out of the way
9+
match (0u8,) {
10+
(0 | _,) => {}
11+
//~^ ERROR or-patterns are not fully implemented yet
12+
}
13+
14+
match (0u8, 0u8) {
15+
//~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)`
16+
(0 | 1, 2 | 3) => {}
17+
}
18+
match ((0u8,),) {
19+
//~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))`
20+
((0 | 1,) | (2 | 3,),) => {},
21+
}
22+
match (Some(0u8),) {
23+
//~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))`
24+
(None | Some(0 | 1),) => {}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered
2+
--> $DIR/exhaustiveness-non-exhaustive.rs:14:11
3+
|
4+
LL | match (0u8, 0u8) {
5+
| ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered
6+
|
7+
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
8+
9+
error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered
10+
--> $DIR/exhaustiveness-non-exhaustive.rs:18:11
11+
|
12+
LL | match ((0u8,),) {
13+
| ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered
14+
|
15+
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
16+
17+
error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered
18+
--> $DIR/exhaustiveness-non-exhaustive.rs:22:11
19+
|
20+
LL | match (Some(0u8),) {
21+
| ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered
22+
|
23+
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
24+
25+
error: or-patterns are not fully implemented yet
26+
--> $DIR/exhaustiveness-non-exhaustive.rs:10:10
27+
|
28+
LL | (0 | _,) => {}
29+
| ^^^^^
30+
31+
error: aborting due to 4 previous errors
32+
33+
For more information about this error, try `rustc --explain E0004`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![feature(or_patterns)]
2+
#![feature(slice_patterns)]
3+
#![allow(incomplete_features)]
4+
#![deny(unreachable_patterns)]
5+
6+
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
7+
fn main() {
8+
// Get the fatal error out of the way
9+
match (0u8,) {
10+
(0 | _,) => {}
11+
//~^ ERROR or-patterns are not fully implemented yet
12+
}
13+
14+
match (0u8,) {
15+
(1 | 2,) => {}
16+
_ => {}
17+
}
18+
19+
match (0u8,) {
20+
(1 | 1,) => {} // FIXME(or_patterns): redundancy not detected for now.
21+
_ => {}
22+
}
23+
match (0u8, 0u8) {
24+
(1 | 2, 3 | 4) => {}
25+
(1, 2) => {}
26+
(2, 1) => {}
27+
_ => {}
28+
}
29+
match (Some(0u8),) {
30+
(None | Some(0 | 1),) => {}
31+
(Some(2..=255),) => {}
32+
}
33+
match ((0u8,),) {
34+
((0 | 1,) | (2 | 3,),) => {},
35+
((_,),) => {},
36+
}
37+
match (&[0u8][..],) {
38+
([] | [0 | 1..=255] | [_, ..],) => {},
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: or-patterns are not fully implemented yet
2+
--> $DIR/exhaustiveness-pass.rs:10:10
3+
|
4+
LL | (0 | _,) => {}
5+
| ^^^^^
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#![feature(or_patterns)]
2+
#![feature(slice_patterns)]
3+
#![allow(incomplete_features)]
4+
#![deny(unreachable_patterns)]
5+
6+
// We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
7+
fn main() {
8+
// Get the fatal error out of the way
9+
match (0u8,) {
10+
(0 | _,) => {}
11+
//~^ ERROR or-patterns are not fully implemented yet
12+
}
13+
14+
match (0u8,) {
15+
(1 | 2,) => {}
16+
(1,) => {} //~ ERROR unreachable pattern
17+
_ => {}
18+
}
19+
match (0u8,) {
20+
(1 | 2,) => {}
21+
(2,) => {} //~ ERROR unreachable pattern
22+
_ => {}
23+
}
24+
match (0u8,) {
25+
(1,) => {}
26+
(2,) => {}
27+
(1 | 2,) => {} //~ ERROR unreachable pattern
28+
_ => {}
29+
}
30+
match (0u8, 0u8) {
31+
(1 | 2, 3 | 4) => {}
32+
(1, 3) => {} //~ ERROR unreachable pattern
33+
(1, 4) => {} //~ ERROR unreachable pattern
34+
(2, 4) => {} //~ ERROR unreachable pattern
35+
(2 | 1, 4) => {} //~ ERROR unreachable pattern
36+
(1, 5 | 6) => {}
37+
(1, 4 | 5) => {} //~ ERROR unreachable pattern
38+
_ => {}
39+
}
40+
match (Some(0u8),) {
41+
(None | Some(1 | 2),) => {}
42+
(Some(1),) => {} //~ ERROR unreachable pattern
43+
(None,) => {} //~ ERROR unreachable pattern
44+
_ => {}
45+
}
46+
match ((0u8,),) {
47+
((1 | 2,) | (3 | 4,),) => {},
48+
((1..=4,),) => {}, //~ ERROR unreachable pattern
49+
_ => {},
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
error: unreachable pattern
2+
--> $DIR/exhaustiveness-unreachable-pattern.rs:16:9
3+
|
4+
LL | (1,) => {}
5+
| ^^^^
6+
|
7+
note: lint level defined here
8+
--> $DIR/exhaustiveness-unreachable-pattern.rs:4:9
9+
|
10+
LL | #![deny(unreachable_patterns)]
11+
| ^^^^^^^^^^^^^^^^^^^^
12+
13+
error: unreachable pattern
14+
--> $DIR/exhaustiveness-unreachable-pattern.rs:21:9
15+
|
16+
LL | (2,) => {}
17+
| ^^^^
18+
19+
error: unreachable pattern
20+
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
21+
|
22+
LL | (1 | 2,) => {}
23+
| ^^^^^^^^
24+
25+
error: unreachable pattern
26+
--> $DIR/exhaustiveness-unreachable-pattern.rs:32:9
27+
|
28+
LL | (1, 3) => {}
29+
| ^^^^^^
30+
31+
error: unreachable pattern
32+
--> $DIR/exhaustiveness-unreachable-pattern.rs:33:9
33+
|
34+
LL | (1, 4) => {}
35+
| ^^^^^^
36+
37+
error: unreachable pattern
38+
--> $DIR/exhaustiveness-unreachable-pattern.rs:34:9
39+
|
40+
LL | (2, 4) => {}
41+
| ^^^^^^
42+
43+
error: unreachable pattern
44+
--> $DIR/exhaustiveness-unreachable-pattern.rs:35:9
45+
|
46+
LL | (2 | 1, 4) => {}
47+
| ^^^^^^^^^^
48+
49+
error: unreachable pattern
50+
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
51+
|
52+
LL | (1, 4 | 5) => {}
53+
| ^^^^^^^^^^
54+
55+
error: unreachable pattern
56+
--> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
57+
|
58+
LL | (Some(1),) => {}
59+
| ^^^^^^^^^^
60+
61+
error: unreachable pattern
62+
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
63+
|
64+
LL | (None,) => {}
65+
| ^^^^^^^
66+
67+
error: unreachable pattern
68+
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
69+
|
70+
LL | ((1..=4,),) => {},
71+
| ^^^^^^^^^^^
72+
73+
error: or-patterns are not fully implemented yet
74+
--> $DIR/exhaustiveness-unreachable-pattern.rs:10:10
75+
|
76+
LL | (0 | _,) => {}
77+
| ^^^^^
78+
79+
error: aborting due to 12 previous errors
80+

0 commit comments

Comments
 (0)