Skip to content

Commit

Permalink
Auto merge of rust-lang#116042 - Nadrieril:linear-pass-take-2, r=<try>
Browse files Browse the repository at this point in the history
[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`
  • Loading branch information
bors committed Nov 4, 2023
2 parents f1b104f + fc12224 commit 6ce98c7
Show file tree
Hide file tree
Showing 45 changed files with 1,605 additions and 1,373 deletions.
834 changes: 400 additions & 434 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Large diffs are not rendered by default.

212 changes: 75 additions & 137 deletions compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

Large diffs are not rendered by default.

874 changes: 503 additions & 371 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ LL | let _b = || { match l1 { L1::A => () } };
| ^^ pattern `L1::B` not covered
|
note: `L1` defined here
--> $DIR/non-exhaustive-match.rs:12:14
--> $DIR/non-exhaustive-match.rs:12:6
|
LL | enum L1 { A, B }
| -- ^ not covered
| ^^ - not covered
= note: the matched value is of type `L1`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/error-codes/E0004.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ LL | match x {
| ^ pattern `Terminator::HastaLaVistaBaby` not covered
|
note: `Terminator` defined here
--> $DIR/E0004.rs:2:5
--> $DIR/E0004.rs:1:6
|
LL | enum Terminator {
| ----------
| ^^^^^^^^^^
LL | HastaLaVistaBaby,
| ^^^^^^^^^^^^^^^^ not covered
| ---------------- not covered
= note: the matched value is of type `Terminator`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ LL | match Foo::A {
| ^^^^^^ pattern `Foo::C` not covered
|
note: `Foo` defined here
--> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9
--> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:10
|
LL | enum Foo {
| ---
| ^^^
...
LL | C,
| ^ not covered
| - not covered
= note: the matched value is of type `Foo`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/match/match_non_exhaustive.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ LL | match l { L::A => () };
| ^ pattern `L::B` not covered
|
note: `L` defined here
--> $DIR/match_non_exhaustive.rs:10:13
--> $DIR/match_non_exhaustive.rs:10:6
|
LL | enum L { A, B }
| - ^ not covered
| ^ - not covered
= note: the matched value is of type `L`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/or-patterns/exhaustiveness-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ fn main() {
((0, 0) | (1, 0),) => {}
_ => {}
}
match ((0, 0),) {
((x, y) | (y, x),) if x == 0 => {}
_ => {}
}
match 0 {
0 | 0 if 0 == 0 => {}
_ => {}
}

// This one caused ICE https://github.com/rust-lang/rust/issues/117378
match (0u8, 0) {
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![deny(unreachable_patterns)]

// We wrap patterns in a tuple because top-level or-patterns were special-cased.
#[rustfmt::skip]
fn main() {
match (0u8,) {
(1 | 2,) => {}
Expand Down Expand Up @@ -73,6 +74,11 @@ fn main() {
| 0] => {} //~ ERROR unreachable
_ => {}
}
match (true, 0) {
(true, 0 | 0) => {} //~ ERROR unreachable
(_, 0 | 0) => {} //~ ERROR unreachable
_ => {}
}
match &[][..] {
[0] => {}
[0, _] => {}
Expand Down Expand Up @@ -149,4 +155,8 @@ fn main() {
| true, //~ ERROR unreachable
false | true) => {}
}
match (true, true) {
(x, y)
| (y, x) => {} //~ ERROR unreachable
}
}
72 changes: 45 additions & 27 deletions tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:7:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:8:9
|
LL | (1,) => {}
| ^^^^
Expand All @@ -11,128 +11,140 @@ LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:12:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:13:9
|
LL | (2,) => {}
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:18:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
|
LL | (1 | 2,) => {}
| ^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:23:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
|
LL | (1, 3) => {}
| ^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
|
LL | (1, 4) => {}
| ^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
|
LL | (2, 4) => {}
| ^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
|
LL | (2 | 1, 4) => {}
| ^^^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:28:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
|
LL | (1, 4 | 5) => {}
| ^^^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:36:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
|
LL | (Some(1),) => {}
| ^^^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:38:9
|
LL | (None,) => {}
| ^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
|
LL | ((1..=4,),) => {}
| ^^^^^^^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:47:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:14
|
LL | (1 | 1,) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:51:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
|
LL | (0 | 1) | 1 => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
|
LL | 0 | (0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:18
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
|
LL | 0 | (0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:65:13
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
|
LL | / Some(
LL | | 0 | 0) => {}
| |______________________^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
|
LL | | 0
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:73:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
|
LL | | 0] => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:81:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:78:20
|
LL | (true, 0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:79:17
|
LL | (_, 0 | 0) => {}
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:87:10
|
LL | [1
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:93:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:99:10
|
LL | [true
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:100:36
--> $DIR/exhaustiveness-unreachable-pattern.rs:106:36
|
LL | (true | false, None | Some(true
| ^^^^

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

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:116:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:122:14
|
LL | Some(0
| ^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:135:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:141:19
|
LL | | false) => {}
| ^^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:143:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
|
LL | | true) => {}
| ^^^^

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:155:15
|
LL | | true,
| ^^^^

error: aborting due to 26 previous errors
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:160:15
|
LL | | (y, x) => {}
| ^^^^^^

error: aborting due to 29 previous errors

4 changes: 2 additions & 2 deletions tests/ui/pattern/issue-94866.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ LL | match Enum::A {
| ^^^^^^^ pattern `Enum::B` not covered
|
note: `Enum` defined here
--> $DIR/issue-94866.rs:7:16
--> $DIR/issue-94866.rs:7:6
|
LL | enum Enum { A, B }
| ---- ^ not covered
| ^^^^ - not covered
= note: the matched value is of type `Enum`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
Expand Down
24 changes: 24 additions & 0 deletions tests/ui/pattern/usefulness/conflicting_bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(if_let_guard, let_chains)]

fn main() {
let mut x = Some(String::new());
let ref mut y @ ref mut z = x;
//~^ ERROR: mutable more than once
let Some(ref mut y @ ref mut z) = x else { return };
//~^ ERROR: mutable more than once
if let Some(ref mut y @ ref mut z) = x {}
//~^ ERROR: mutable more than once
if let Some(ref mut y @ ref mut z) = x && true {}
//~^ ERROR: mutable more than once
while let Some(ref mut y @ ref mut z) = x {}
//~^ ERROR: mutable more than once
while let Some(ref mut y @ ref mut z) = x && true {}
//~^ ERROR: mutable more than once
match x {
ref mut y @ ref mut z => {} //~ ERROR: mutable more than once
}
match () {
() if let Some(ref mut y @ ref mut z) = x => {} //~ ERROR: mutable more than once
_ => {}
}
}
Loading

0 comments on commit 6ce98c7

Please sign in to comment.