Skip to content

Commit c703bf4

Browse files
committed
Auto merge of rust-lang#119031 - Nadrieril:two-phase-match-lowering, r=<try>
[Experiment] Play with match lowering Match lowering to MIR has the reputation of being the most intricate piece of the compiler, and after banging my head on it for a bit I sure hope there isn't anything more intricate somewhere else. It's good quality code but I hope to unentangle it. This PR is me wrestling with it and asking `rustc-timer` for its opinion. r? `@ghost`
2 parents 5119208 + 6433f90 commit c703bf4

16 files changed

+373
-389
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+178-156
Large diffs are not rendered by default.

compiler/rustc_mir_build/src/build/matches/test.rs

+90-173
Large diffs are not rendered by default.

compiler/rustc_mir_build/src/build/matches/util.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
122122
let mut subpairs = Vec::new();
123123
let test_case = match pattern.kind {
124124
PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
125-
PatKind::Or { ref pats } => TestCase::Or {
126-
pats: pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect(),
127-
},
125+
PatKind::Or { ref pats } => {
126+
let pats: Box<[_]> =
127+
pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect();
128+
let simple = pats.iter().all(|fpat| fpat.simple);
129+
TestCase::Or { pats, simple }
130+
}
128131

129132
PatKind::Range(ref range) => {
130133
if range.is_full_range(cx.tcx) == Some(true) {
@@ -260,6 +263,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
260263

261264
MatchPair { place, test_case, subpairs, pattern }
262265
}
266+
267+
/// Whether this recursively contains no bindings or ascriptions.
268+
pub(super) fn is_simple(&self) -> bool {
269+
!matches!(self.test_case, TestCase::Or { simple: false, .. })
270+
&& self.subpairs.iter().all(|p| p.is_simple())
271+
}
263272
}
264273

265274
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {

tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn full_tested_match() -> () {
2828
_2 = Option::<i32>::Some(const 42_i32);
2929
PlaceMention(_2);
3030
_3 = discriminant(_2);
31-
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
31+
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
3232
}
3333

3434
bb1: {
@@ -37,20 +37,20 @@ fn full_tested_match() -> () {
3737
}
3838

3939
bb2: {
40-
_1 = (const 3_i32, const 3_i32);
41-
goto -> bb13;
40+
falseEdge -> [real: bb7, imaginary: bb3];
4241
}
4342

4443
bb3: {
45-
goto -> bb1;
44+
falseEdge -> [real: bb12, imaginary: bb5];
4645
}
4746

4847
bb4: {
49-
falseEdge -> [real: bb7, imaginary: bb5];
48+
goto -> bb1;
5049
}
5150

5251
bb5: {
53-
falseEdge -> [real: bb12, imaginary: bb2];
52+
_1 = (const 3_i32, const 3_i32);
53+
goto -> bb13;
5454
}
5555

5656
bb6: {
@@ -91,7 +91,7 @@ fn full_tested_match() -> () {
9191
bb11: {
9292
StorageDead(_7);
9393
StorageDead(_6);
94-
goto -> bb5;
94+
goto -> bb3;
9595
}
9696

9797
bb12: {

tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir

+11-11
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn full_tested_match2() -> () {
2828
_2 = Option::<i32>::Some(const 42_i32);
2929
PlaceMention(_2);
3030
_3 = discriminant(_2);
31-
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
31+
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
3232
}
3333

3434
bb1: {
@@ -37,18 +37,10 @@ fn full_tested_match2() -> () {
3737
}
3838

3939
bb2: {
40-
falseEdge -> [real: bb12, imaginary: bb5];
40+
falseEdge -> [real: bb7, imaginary: bb5];
4141
}
4242

4343
bb3: {
44-
goto -> bb1;
45-
}
46-
47-
bb4: {
48-
falseEdge -> [real: bb7, imaginary: bb2];
49-
}
50-
51-
bb5: {
5244
StorageLive(_9);
5345
_9 = ((_2 as Some).0: i32);
5446
StorageLive(_10);
@@ -59,6 +51,14 @@ fn full_tested_match2() -> () {
5951
goto -> bb13;
6052
}
6153

54+
bb4: {
55+
goto -> bb1;
56+
}
57+
58+
bb5: {
59+
falseEdge -> [real: bb12, imaginary: bb3];
60+
}
61+
6262
bb6: {
6363
goto -> bb1;
6464
}
@@ -97,7 +97,7 @@ fn full_tested_match2() -> () {
9797
bb11: {
9898
StorageDead(_7);
9999
StorageDead(_6);
100-
falseEdge -> [real: bb5, imaginary: bb2];
100+
falseEdge -> [real: bb3, imaginary: bb5];
101101
}
102102

103103
bb12: {

tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
StorageDead(_5);
3131
StorageDead(_4);
3232
_8 = discriminant((_3.0: std::option::Option<u32>));
33-
- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1];
33+
- switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
3434
+ StorageLive(_11);
3535
+ _11 = discriminant((_3.1: std::option::Option<u32>));
3636
+ StorageLive(_12);
@@ -48,12 +48,12 @@
4848

4949
bb2: {
5050
- _6 = discriminant((_3.1: std::option::Option<u32>));
51-
- switchInt(move _6) -> [0: bb5, otherwise: bb1];
51+
- switchInt(move _6) -> [1: bb4, otherwise: bb1];
5252
- }
5353
-
5454
- bb3: {
5555
- _7 = discriminant((_3.1: std::option::Option<u32>));
56-
- switchInt(move _7) -> [1: bb4, otherwise: bb1];
56+
- switchInt(move _7) -> [0: bb5, otherwise: bb1];
5757
- }
5858
-
5959
- bb4: {

tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff

+6-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
StorageDead(_5);
3737
StorageDead(_4);
3838
_8 = discriminant((_3.0: std::option::Option<u32>));
39-
switchInt(move _8) -> [0: bb2, 1: bb4, otherwise: bb1];
39+
switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
4040
}
4141

4242
bb1: {
@@ -45,17 +45,17 @@
4545

4646
bb2: {
4747
_6 = discriminant((_3.1: std::option::Option<u32>));
48-
switchInt(move _6) -> [0: bb3, 1: bb7, otherwise: bb1];
48+
switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1];
4949
}
5050

5151
bb3: {
52-
_0 = const 3_u32;
53-
goto -> bb8;
52+
_7 = discriminant((_3.1: std::option::Option<u32>));
53+
switchInt(move _7) -> [0: bb4, 1: bb7, otherwise: bb1];
5454
}
5555

5656
bb4: {
57-
_7 = discriminant((_3.1: std::option::Option<u32>));
58-
switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb1];
57+
_0 = const 3_u32;
58+
goto -> bb8;
5959
}
6060

6161
bb5: {

tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff

+8-7
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@
4242
}
4343

4444
bb2: {
45-
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
45+
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
4646
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
4747
}
4848

4949
bb3: {
50+
- falseEdge -> [real: bb20, imaginary: bb4];
51+
- }
52+
-
53+
- bb4: {
5054
StorageLive(_15);
5155
_15 = (_2.1: bool);
5256
StorageLive(_16);
@@ -55,19 +59,16 @@
5559
+ goto -> bb16;
5660
}
5761

58-
bb4: {
59-
- falseEdge -> [real: bb20, imaginary: bb3];
60-
- }
61-
-
6262
- bb5: {
63-
- falseEdge -> [real: bb13, imaginary: bb4];
63+
- falseEdge -> [real: bb13, imaginary: bb3];
6464
- }
6565
-
6666
- bb6: {
6767
- falseEdge -> [real: bb8, imaginary: bb5];
6868
- }
6969
-
7070
- bb7: {
71+
+ bb4: {
7172
_0 = const 1_i32;
7273
- drop(_7) -> [return: bb18, unwind: bb25];
7374
+ drop(_7) -> [return: bb15, unwind: bb22];
@@ -183,7 +184,7 @@
183184
StorageDead(_12);
184185
StorageDead(_8);
185186
StorageDead(_6);
186-
- falseEdge -> [real: bb2, imaginary: bb4];
187+
- falseEdge -> [real: bb2, imaginary: bb3];
187188
+ goto -> bb2;
188189
}
189190

tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff

+8-7
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@
4242
}
4343

4444
bb2: {
45-
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
45+
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
4646
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
4747
}
4848

4949
bb3: {
50+
- falseEdge -> [real: bb20, imaginary: bb4];
51+
- }
52+
-
53+
- bb4: {
5054
StorageLive(_15);
5155
_15 = (_2.1: bool);
5256
StorageLive(_16);
@@ -55,19 +59,16 @@
5559
+ goto -> bb16;
5660
}
5761

58-
bb4: {
59-
- falseEdge -> [real: bb20, imaginary: bb3];
60-
- }
61-
-
6262
- bb5: {
63-
- falseEdge -> [real: bb13, imaginary: bb4];
63+
- falseEdge -> [real: bb13, imaginary: bb3];
6464
- }
6565
-
6666
- bb6: {
6767
- falseEdge -> [real: bb8, imaginary: bb5];
6868
- }
6969
-
7070
- bb7: {
71+
+ bb4: {
7172
_0 = const 1_i32;
7273
- drop(_7) -> [return: bb18, unwind: bb25];
7374
+ drop(_7) -> [return: bb15, unwind: bb22];
@@ -183,7 +184,7 @@
183184
StorageDead(_12);
184185
StorageDead(_8);
185186
StorageDead(_6);
186-
- falseEdge -> [real: bb2, imaginary: bb4];
187+
- falseEdge -> [real: bb2, imaginary: bb3];
187188
+ goto -> bb2;
188189
}
189190

tests/ui/or-patterns/bindings-runpass-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ fn main() {
2626
assert_eq!(or_at(Err(7)), 207);
2727
assert_eq!(or_at(Err(8)), 8);
2828
assert_eq!(or_at(Err(20)), 220);
29+
assert_eq!(or_at(Err(34)), 134);
2930
assert_eq!(or_at(Err(50)), 500);
3031
}

tests/ui/or-patterns/inner-or-pat.or3.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/inner-or-pat.rs:38:54
2+
--> $DIR/inner-or-pat.rs:36:54
33
|
44
LL | match x {
55
| - this expression has type `&str`

tests/ui/or-patterns/inner-or-pat.or4.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0408]: variable `x` is not bound in all patterns
2-
--> $DIR/inner-or-pat.rs:53:37
2+
--> $DIR/inner-or-pat.rs:51:37
33
|
44
LL | (x @ "red" | (x @ "blue" | "red")) => {
55
| - ^^^^^ pattern doesn't bind `x`

tests/ui/or-patterns/inner-or-pat.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
//@ revisions: or1 or2 or3 or4 or5
1+
//@ revisions: or1 or3 or4
22
//@ [or1] run-pass
3-
//@ [or2] run-pass
4-
//@ [or5] run-pass
53

64
#![allow(unreachable_patterns)]
75
#![allow(unused_variables)]
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
//@ check-pass
1+
//@ run-pass
22

33
#![deny(unreachable_patterns)]
44

55
fn main() {
6-
match (3,42) {
7-
(a,_) | (_,a) if a > 10 => {println!("{}", a)}
8-
_ => ()
6+
match (3, 42) {
7+
(a, _) | (_, a) if a > 10 => {}
8+
_ => unreachable!(),
99
}
1010

11-
match Some((3,42)) {
12-
Some((a, _)) | Some((_, a)) if a > 10 => {println!("{}", a)}
13-
_ => ()
14-
11+
match Some((3, 42)) {
12+
Some((a, _)) | Some((_, a)) if a > 10 => {}
13+
_ => unreachable!(),
1514
}
1615

17-
match Some((3,42)) {
18-
Some((a, _) | (_, a)) if a > 10 => {println!("{}", a)}
19-
_ => ()
16+
match Some((3, 42)) {
17+
Some((a, _) | (_, a)) if a > 10 => {}
18+
_ => unreachable!(),
2019
}
2120
}

tests/ui/or-patterns/search-via-bindings.rs

+22
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@ fn search_old_style(target: (bool, bool, bool)) -> u32 {
4242
}
4343
}
4444

45+
// Check that a dummy or-pattern also leads to running the guard multiple times.
46+
fn search_with_dummy(target: (bool, bool)) -> u32 {
47+
let x = ((false, true), (false, true), ());
48+
let mut guard_count = 0;
49+
match x {
50+
((a, _) | (_, a), (b, _) | (_, b), _ | _)
51+
if {
52+
guard_count += 1;
53+
(a, b) == target
54+
} =>
55+
{
56+
guard_count
57+
}
58+
_ => unreachable!(),
59+
}
60+
}
61+
4562
fn main() {
4663
assert_eq!(search((false, false, false)), 1);
4764
assert_eq!(search((false, false, true)), 2);
@@ -60,4 +77,9 @@ fn main() {
6077
assert_eq!(search_old_style((true, false, true)), 6);
6178
assert_eq!(search_old_style((true, true, false)), 7);
6279
assert_eq!(search_old_style((true, true, true)), 8);
80+
81+
assert_eq!(search_with_dummy((false, false)), 1);
82+
assert_eq!(search_with_dummy((false, true)), 3);
83+
assert_eq!(search_with_dummy((true, false)), 5);
84+
assert_eq!(search_with_dummy((true, true)), 7);
6385
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ run-pass
2+
//
3+
// Regression test for match lowering to MIR: when gathering candidates, by the time we get to the
4+
// range we know the range will only match on the failure case of the switchint. Hence we mustn't
5+
// add the `1` to the switchint or the range would be incorrectly sorted.
6+
#![allow(unreachable_patterns)]
7+
fn main() {
8+
match 1 {
9+
10 => unreachable!(),
10+
0..=5 => {}
11+
1 => unreachable!(),
12+
_ => unreachable!(),
13+
}
14+
}

0 commit comments

Comments
 (0)