Skip to content

Commit 6ce98c7

Browse files
committed
Auto merge of rust-lang#116042 - Nadrieril:linear-pass-take-2, r=<try>
[Experiment] Rewrite exhaustiveness in one pass Arm reachability checking does a quadratic amount of work: for each arm we check if it is reachable given the arms above it. This feels wasteful since we often end up re-exploring the same cases when we check for exhaustiveness. This PR is an attempt to check reachability at the same time as exhaustiveness. This opens the door to a bunch of code simplifications I'm very excited about. The main question is whether I can get actual performance gains out of this. I had started the experiment in rust-lang#111720 but I can't reopen it. r? `@ghost`
2 parents f1b104f + fc12224 commit 6ce98c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1605
-1373
lines changed

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

+400-434
Large diffs are not rendered by default.

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

+75-137
Large diffs are not rendered by default.

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

+503-371
Large diffs are not rendered by default.

tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ LL | let _b = || { match l1 { L1::A => () } };
55
| ^^ pattern `L1::B` not covered
66
|
77
note: `L1` defined here
8-
--> $DIR/non-exhaustive-match.rs:12:14
8+
--> $DIR/non-exhaustive-match.rs:12:6
99
|
1010
LL | enum L1 { A, B }
11-
| -- ^ not covered
11+
| ^^ - not covered
1212
= note: the matched value is of type `L1`
1313
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1414
|

tests/ui/error-codes/E0004.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ LL | match x {
55
| ^ pattern `Terminator::HastaLaVistaBaby` not covered
66
|
77
note: `Terminator` defined here
8-
--> $DIR/E0004.rs:2:5
8+
--> $DIR/E0004.rs:1:6
99
|
1010
LL | enum Terminator {
11-
| ----------
11+
| ^^^^^^^^^^
1212
LL | HastaLaVistaBaby,
13-
| ^^^^^^^^^^^^^^^^ not covered
13+
| ---------------- not covered
1414
= note: the matched value is of type `Terminator`
1515
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1616
|

tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,13 @@ LL | match Foo::A {
134134
| ^^^^^^ pattern `Foo::C` not covered
135135
|
136136
note: `Foo` defined here
137-
--> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9
137+
--> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:10
138138
|
139139
LL | enum Foo {
140-
| ---
140+
| ^^^
141141
...
142142
LL | C,
143-
| ^ not covered
143+
| - not covered
144144
= note: the matched value is of type `Foo`
145145
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
146146
|

tests/ui/match/match_non_exhaustive.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ LL | match l { L::A => () };
55
| ^ pattern `L::B` not covered
66
|
77
note: `L` defined here
8-
--> $DIR/match_non_exhaustive.rs:10:13
8+
--> $DIR/match_non_exhaustive.rs:10:6
99
|
1010
LL | enum L { A, B }
11-
| - ^ not covered
11+
| ^ - not covered
1212
= note: the matched value is of type `L`
1313
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1414
|

tests/ui/or-patterns/exhaustiveness-pass.rs

+8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ fn main() {
3535
((0, 0) | (1, 0),) => {}
3636
_ => {}
3737
}
38+
match ((0, 0),) {
39+
((x, y) | (y, x),) if x == 0 => {}
40+
_ => {}
41+
}
42+
match 0 {
43+
0 | 0 if 0 == 0 => {}
44+
_ => {}
45+
}
3846

3947
// This one caused ICE https://github.com/rust-lang/rust/issues/117378
4048
match (0u8, 0) {

tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![deny(unreachable_patterns)]
22

33
// We wrap patterns in a tuple because top-level or-patterns were special-cased.
4+
#[rustfmt::skip]
45
fn main() {
56
match (0u8,) {
67
(1 | 2,) => {}
@@ -73,6 +74,11 @@ fn main() {
7374
| 0] => {} //~ ERROR unreachable
7475
_ => {}
7576
}
77+
match (true, 0) {
78+
(true, 0 | 0) => {} //~ ERROR unreachable
79+
(_, 0 | 0) => {} //~ ERROR unreachable
80+
_ => {}
81+
}
7682
match &[][..] {
7783
[0] => {}
7884
[0, _] => {}
@@ -149,4 +155,8 @@ fn main() {
149155
| true, //~ ERROR unreachable
150156
false | true) => {}
151157
}
158+
match (true, true) {
159+
(x, y)
160+
| (y, x) => {} //~ ERROR unreachable
161+
}
152162
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unreachable pattern
2-
--> $DIR/exhaustiveness-unreachable-pattern.rs:7:9
2+
--> $DIR/exhaustiveness-unreachable-pattern.rs:8:9
33
|
44
LL | (1,) => {}
55
| ^^^^
@@ -11,128 +11,140 @@ LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error: unreachable pattern
14-
--> $DIR/exhaustiveness-unreachable-pattern.rs:12:9
14+
--> $DIR/exhaustiveness-unreachable-pattern.rs:13:9
1515
|
1616
LL | (2,) => {}
1717
| ^^^^
1818

1919
error: unreachable pattern
20-
--> $DIR/exhaustiveness-unreachable-pattern.rs:18:9
20+
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
2121
|
2222
LL | (1 | 2,) => {}
2323
| ^^^^^^^^
2424

2525
error: unreachable pattern
26-
--> $DIR/exhaustiveness-unreachable-pattern.rs:23:9
26+
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
2727
|
2828
LL | (1, 3) => {}
2929
| ^^^^^^
3030

3131
error: unreachable pattern
32-
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
32+
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
3333
|
3434
LL | (1, 4) => {}
3535
| ^^^^^^
3636

3737
error: unreachable pattern
38-
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
38+
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
3939
|
4040
LL | (2, 4) => {}
4141
| ^^^^^^
4242

4343
error: unreachable pattern
44-
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
44+
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
4545
|
4646
LL | (2 | 1, 4) => {}
4747
| ^^^^^^^^^^
4848

4949
error: unreachable pattern
50-
--> $DIR/exhaustiveness-unreachable-pattern.rs:28:9
50+
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
5151
|
5252
LL | (1, 4 | 5) => {}
5353
| ^^^^^^^^^^
5454

5555
error: unreachable pattern
56-
--> $DIR/exhaustiveness-unreachable-pattern.rs:36:9
56+
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
5757
|
5858
LL | (Some(1),) => {}
5959
| ^^^^^^^^^^
6060

6161
error: unreachable pattern
62-
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
62+
--> $DIR/exhaustiveness-unreachable-pattern.rs:38:9
6363
|
6464
LL | (None,) => {}
6565
| ^^^^^^^
6666

6767
error: unreachable pattern
68-
--> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
68+
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
6969
|
7070
LL | ((1..=4,),) => {}
7171
| ^^^^^^^^^^^
7272

7373
error: unreachable pattern
74-
--> $DIR/exhaustiveness-unreachable-pattern.rs:47:14
74+
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:14
7575
|
7676
LL | (1 | 1,) => {}
7777
| ^
7878

7979
error: unreachable pattern
80-
--> $DIR/exhaustiveness-unreachable-pattern.rs:51:19
80+
--> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
8181
|
8282
LL | (0 | 1) | 1 => {}
8383
| ^
8484

8585
error: unreachable pattern
86-
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:14
86+
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
8787
|
8888
LL | 0 | (0 | 0) => {}
8989
| ^
9090

9191
error: unreachable pattern
92-
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:18
92+
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
9393
|
9494
LL | 0 | (0 | 0) => {}
9595
| ^
9696

9797
error: unreachable pattern
98-
--> $DIR/exhaustiveness-unreachable-pattern.rs:65:13
98+
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
9999
|
100100
LL | / Some(
101101
LL | | 0 | 0) => {}
102102
| |______________________^
103103

104104
error: unreachable pattern
105-
--> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
105+
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
106106
|
107107
LL | | 0
108108
| ^
109109

110110
error: unreachable pattern
111-
--> $DIR/exhaustiveness-unreachable-pattern.rs:73:15
111+
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
112112
|
113113
LL | | 0] => {}
114114
| ^
115115

116116
error: unreachable pattern
117-
--> $DIR/exhaustiveness-unreachable-pattern.rs:81:10
117+
--> $DIR/exhaustiveness-unreachable-pattern.rs:78:20
118+
|
119+
LL | (true, 0 | 0) => {}
120+
| ^
121+
122+
error: unreachable pattern
123+
--> $DIR/exhaustiveness-unreachable-pattern.rs:79:17
124+
|
125+
LL | (_, 0 | 0) => {}
126+
| ^
127+
128+
error: unreachable pattern
129+
--> $DIR/exhaustiveness-unreachable-pattern.rs:87:10
118130
|
119131
LL | [1
120132
| ^
121133

122134
error: unreachable pattern
123-
--> $DIR/exhaustiveness-unreachable-pattern.rs:93:10
135+
--> $DIR/exhaustiveness-unreachable-pattern.rs:99:10
124136
|
125137
LL | [true
126138
| ^^^^
127139

128140
error: unreachable pattern
129-
--> $DIR/exhaustiveness-unreachable-pattern.rs:100:36
141+
--> $DIR/exhaustiveness-unreachable-pattern.rs:106:36
130142
|
131143
LL | (true | false, None | Some(true
132144
| ^^^^
133145

134146
error: unreachable pattern
135-
--> $DIR/exhaustiveness-unreachable-pattern.rs:105:14
147+
--> $DIR/exhaustiveness-unreachable-pattern.rs:111:14
136148
|
137149
LL | (true
138150
| ^^^^
@@ -143,28 +155,34 @@ LL | (true | false, None | Some(t_or_f!())) => {}
143155
= note: this error originates in the macro `t_or_f` (in Nightly builds, run with -Z macro-backtrace for more info)
144156

145157
error: unreachable pattern
146-
--> $DIR/exhaustiveness-unreachable-pattern.rs:116:14
158+
--> $DIR/exhaustiveness-unreachable-pattern.rs:122:14
147159
|
148160
LL | Some(0
149161
| ^
150162

151163
error: unreachable pattern
152-
--> $DIR/exhaustiveness-unreachable-pattern.rs:135:19
164+
--> $DIR/exhaustiveness-unreachable-pattern.rs:141:19
153165
|
154166
LL | | false) => {}
155167
| ^^^^^
156168

157169
error: unreachable pattern
158-
--> $DIR/exhaustiveness-unreachable-pattern.rs:143:15
170+
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
159171
|
160172
LL | | true) => {}
161173
| ^^^^
162174

163175
error: unreachable pattern
164-
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
176+
--> $DIR/exhaustiveness-unreachable-pattern.rs:155:15
165177
|
166178
LL | | true,
167179
| ^^^^
168180

169-
error: aborting due to 26 previous errors
181+
error: unreachable pattern
182+
--> $DIR/exhaustiveness-unreachable-pattern.rs:160:15
183+
|
184+
LL | | (y, x) => {}
185+
| ^^^^^^
186+
187+
error: aborting due to 29 previous errors
170188

tests/ui/pattern/issue-94866.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ LL | match Enum::A {
55
| ^^^^^^^ pattern `Enum::B` not covered
66
|
77
note: `Enum` defined here
8-
--> $DIR/issue-94866.rs:7:16
8+
--> $DIR/issue-94866.rs:7:6
99
|
1010
LL | enum Enum { A, B }
11-
| ---- ^ not covered
11+
| ^^^^ - not covered
1212
= note: the matched value is of type `Enum`
1313
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1414
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(if_let_guard, let_chains)]
2+
3+
fn main() {
4+
let mut x = Some(String::new());
5+
let ref mut y @ ref mut z = x;
6+
//~^ ERROR: mutable more than once
7+
let Some(ref mut y @ ref mut z) = x else { return };
8+
//~^ ERROR: mutable more than once
9+
if let Some(ref mut y @ ref mut z) = x {}
10+
//~^ ERROR: mutable more than once
11+
if let Some(ref mut y @ ref mut z) = x && true {}
12+
//~^ ERROR: mutable more than once
13+
while let Some(ref mut y @ ref mut z) = x {}
14+
//~^ ERROR: mutable more than once
15+
while let Some(ref mut y @ ref mut z) = x && true {}
16+
//~^ ERROR: mutable more than once
17+
match x {
18+
ref mut y @ ref mut z => {} //~ ERROR: mutable more than once
19+
}
20+
match () {
21+
() if let Some(ref mut y @ ref mut z) = x => {} //~ ERROR: mutable more than once
22+
_ => {}
23+
}
24+
}

0 commit comments

Comments
 (0)