Auto merge of #80632 - Nadrieril:fix-80501, r=varkor

Identify unreachable subpatterns more reliably

In https://github.com/rust-lang/rust/pull/80104 I used `Span`s to identify unreachable sub-patterns in the presence of or-patterns during exhaustiveness checking. In https://github.com/rust-lang/rust/issues/80501 it was revealed that `Span`s are complicated and that this was not a good idea.
Instead, this PR identifies subpatterns logically: as a path in the tree of subpatterns of a given pattern. I made a struct that captures a set of such subpatterns. This is a bit complex, but thankfully self-contained; the rest of the code does not need to know anything about it.
Fixes https://github.com/rust-lang/rust/issues/80501. I think I managed to keep the perf neutral.

r? `@varkor`
This commit is contained in:
bors 2021-02-07 16:48:57 +00:00
commit 36ecbc94eb
6 changed files with 473 additions and 224 deletions

View file

@ -48,6 +48,25 @@ fn main() {
(1 | 1,) => {} //~ ERROR unreachable
_ => {}
}
match 0 {
(0 | 1) | 1 => {} //~ ERROR unreachable
_ => {}
}
match 0 {
// We get two errors because recursive or-pattern expansion means we don't notice the two
// errors span a whole pattern. This could be better but doesn't matter much
0 | (0 | 0) => {}
//~^ ERROR unreachable
//~| ERROR unreachable
_ => {}
}
match None {
// There is only one error that correctly points to the whole subpattern
Some(0) |
Some( //~ ERROR unreachable
0 | 0) => {}
_ => {}
}
match [0; 2] {
[0
| 0 //~ ERROR unreachable
@ -84,8 +103,8 @@ fn main() {
}
macro_rules! t_or_f {
() => {
(true // FIXME: should be unreachable
| false)
(true //~ ERROR unreachable
| false)
};
}
match (true, None) {

View file

@ -77,58 +77,94 @@ LL | (1 | 1,) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:53:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
|
LL | (0 | 1) | 1 => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
|
LL | 0 | (0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
|
LL | 0 | (0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
|
LL | / Some(
LL | | 0 | 0) => {}
| |______________________^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
|
LL | | 0
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:55:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
|
LL | | 0] => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:63:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:82:10
|
LL | [1
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:75:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:94:10
|
LL | [true
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:82:36
--> $DIR/exhaustiveness-unreachable-pattern.rs:101:36
|
LL | (true | false, None | Some(true
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:98:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:106:14
|
LL | (true
| ^^^^
...
LL | (true | false, None | Some(t_or_f!())) => {}
| --------- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:117:14
|
LL | Some(0
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:117:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:136:19
|
LL | | false) => {}
| ^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:125:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:144:15
|
LL | | true) => {}
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:131:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:150:15
|
LL | | true,
| ^^^^
error: aborting due to 21 previous errors
error: aborting due to 26 previous errors

View file

@ -0,0 +1,27 @@
// check-pass
#![deny(unreachable_patterns)]
pub enum TypeCtor {
Slice,
Array,
}
pub struct ApplicationTy(TypeCtor);
macro_rules! ty_app {
($ctor:pat) => {
ApplicationTy($ctor)
};
}
fn _foo(ty: ApplicationTy) {
match ty {
ty_app!(TypeCtor::Array) | ty_app!(TypeCtor::Slice) => {}
}
// same as above, with the macro expanded
match ty {
ApplicationTy(TypeCtor::Array) | ApplicationTy(TypeCtor::Slice) => {}
}
}
fn main() {}