Skip to content

Commit e450646

Browse files
authored
Rollup merge of rust-lang#73973 - Nadrieril:fix-71977, r=matthewjasper
Use `Span`s to identify unreachable subpatterns in or-patterns Fixes rust-lang#71977
2 parents a1ac4d6 + 3cb31b6 commit e450646

File tree

5 files changed

+90
-25
lines changed

5 files changed

+90
-25
lines changed

src/librustc_mir_build/hair/pattern/_match.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ use self::Usefulness::*;
276276
use self::WitnessPreference::*;
277277

278278
use rustc_data_structures::captures::Captures;
279+
use rustc_data_structures::fx::FxHashSet;
279280
use rustc_index::vec::Idx;
280281

281282
use super::{compare_const_vals, PatternFoldable, PatternFolder};
@@ -1246,15 +1247,15 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12461247
}
12471248

12481249
#[derive(Clone, Debug)]
1249-
crate enum Usefulness<'tcx, 'p> {
1250+
crate enum Usefulness<'tcx> {
12501251
/// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
1251-
Useful(Vec<&'p Pat<'tcx>>),
1252+
Useful(Vec<Span>),
12521253
/// Carries a list of witnesses of non-exhaustiveness.
12531254
UsefulWithWitness(Vec<Witness<'tcx>>),
12541255
NotUseful,
12551256
}
12561257

1257-
impl<'tcx, 'p> Usefulness<'tcx, 'p> {
1258+
impl<'tcx> Usefulness<'tcx> {
12581259
fn new_useful(preference: WitnessPreference) -> Self {
12591260
match preference {
12601261
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
@@ -1269,7 +1270,7 @@ impl<'tcx, 'p> Usefulness<'tcx, 'p> {
12691270
}
12701271
}
12711272

1272-
fn apply_constructor(
1273+
fn apply_constructor<'p>(
12731274
self,
12741275
cx: &MatchCheckCtxt<'p, 'tcx>,
12751276
ctor: &Constructor<'tcx>,
@@ -1828,7 +1829,7 @@ crate fn is_useful<'p, 'tcx>(
18281829
hir_id: HirId,
18291830
is_under_guard: bool,
18301831
is_top_level: bool,
1831-
) -> Usefulness<'tcx, 'p> {
1832+
) -> Usefulness<'tcx> {
18321833
let &Matrix(ref rows) = matrix;
18331834
debug!("is_useful({:#?}, {:#?})", matrix, v);
18341835

@@ -1852,16 +1853,35 @@ crate fn is_useful<'p, 'tcx>(
18521853
// We need to push the already-seen patterns into the matrix in order to detect redundant
18531854
// branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
18541855
let mut matrix = matrix.clone();
1855-
let mut unreachable_pats = Vec::new();
1856+
// `Vec` of all the unreachable branches of the current or-pattern.
1857+
let mut unreachable_branches = Vec::new();
1858+
// Subpatterns that are unreachable from all branches. E.g. in the following case, the last
1859+
// `true` is unreachable only from one branch, so it is overall reachable.
1860+
// ```
1861+
// match (true, true) {
1862+
// (true, true) => {}
1863+
// (false | true, false | true) => {}
1864+
// }
1865+
// ```
1866+
let mut unreachable_subpats = FxHashSet::default();
1867+
// Whether any branch at all is useful.
18561868
let mut any_is_useful = false;
1869+
18571870
for v in vs {
18581871
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
18591872
match res {
18601873
Useful(pats) => {
1861-
any_is_useful = true;
1862-
unreachable_pats.extend(pats);
1874+
if !any_is_useful {
1875+
any_is_useful = true;
1876+
// Initialize with the first set of unreachable subpatterns encountered.
1877+
unreachable_subpats = pats.into_iter().collect();
1878+
} else {
1879+
// Keep the patterns unreachable from both this and previous branches.
1880+
unreachable_subpats =
1881+
pats.into_iter().filter(|p| unreachable_subpats.contains(p)).collect();
1882+
}
18631883
}
1864-
NotUseful => unreachable_pats.push(v.head()),
1884+
NotUseful => unreachable_branches.push(v.head().span),
18651885
UsefulWithWitness(_) => {
18661886
bug!("Encountered or-pat in `v` during exhaustiveness checking")
18671887
}
@@ -1871,7 +1891,13 @@ crate fn is_useful<'p, 'tcx>(
18711891
matrix.push(v);
18721892
}
18731893
}
1874-
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
1894+
if any_is_useful {
1895+
// Collect all the unreachable patterns.
1896+
unreachable_branches.extend(unreachable_subpats);
1897+
return Useful(unreachable_branches);
1898+
} else {
1899+
return NotUseful;
1900+
}
18751901
}
18761902

18771903
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
@@ -2014,7 +2040,7 @@ fn is_useful_specialized<'p, 'tcx>(
20142040
witness_preference: WitnessPreference,
20152041
hir_id: HirId,
20162042
is_under_guard: bool,
2017-
) -> Usefulness<'tcx, 'p> {
2043+
) -> Usefulness<'tcx> {
20182044
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, ty);
20192045

20202046
// We cache the result of `Fields::wildcards` because it is used a lot.

src/librustc_mir_build/hair/pattern/check_match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,8 @@ fn check_arms<'p, 'tcx>(
393393
}
394394
}
395395
Useful(unreachable_subpatterns) => {
396-
for pat in unreachable_subpatterns {
397-
unreachable_pattern(cx.tcx, pat.span, id, None);
396+
for span in unreachable_subpatterns {
397+
unreachable_pattern(cx.tcx, span, id, None);
398398
}
399399
}
400400
UsefulWithWitness(_) => bug!(),

src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs

+28
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ fn main() {
2929
(1, 4 | 5) => {} //~ ERROR unreachable pattern
3030
_ => {}
3131
}
32+
match (true, true) {
33+
(false | true, false | true) => (),
34+
}
3235
match (Some(0u8),) {
3336
(None | Some(1 | 2),) => {}
3437
(Some(1),) => {} //~ ERROR unreachable pattern
@@ -67,4 +70,29 @@ fn main() {
6770
| 1) => {}
6871
_ => {}
6972
}
73+
74+
// A subpattern that is only unreachable in one branch is overall reachable.
75+
match (true, true) {
76+
(true, true) => {}
77+
(false | true, false | true) => {}
78+
}
79+
match (true, true) {
80+
(true, false) => {}
81+
(false, true) => {}
82+
(false | true, false | true) => {}
83+
}
84+
// A subpattern that is unreachable in all branches is overall unreachable.
85+
match (true, true) {
86+
(false, true) => {}
87+
(true, true) => {}
88+
(false | true, false
89+
| true) => {} //~ ERROR unreachable
90+
}
91+
match (true, true) {
92+
(true, false) => {}
93+
(true, true) => {}
94+
(false
95+
| true, //~ ERROR unreachable
96+
false | true) => {}
97+
}
7098
}

src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr

+23-11
Original file line numberDiff line numberDiff line change
@@ -53,52 +53,64 @@ LL | (1, 4 | 5) => {}
5353
| ^^^^^^^^^^
5454

5555
error: unreachable pattern
56-
--> $DIR/exhaustiveness-unreachable-pattern.rs:34: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:35: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:40: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:45: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:52:15
80+
--> $DIR/exhaustiveness-unreachable-pattern.rs:53:15
8181
|
82-
LL | | 0] => {}
82+
LL | | 0
8383
| ^
8484

8585
error: unreachable pattern
86-
--> $DIR/exhaustiveness-unreachable-pattern.rs:50:15
86+
--> $DIR/exhaustiveness-unreachable-pattern.rs:55:15
8787
|
88-
LL | | 0
88+
LL | | 0] => {}
8989
| ^
9090

9191
error: unreachable pattern
92-
--> $DIR/exhaustiveness-unreachable-pattern.rs:60:10
92+
--> $DIR/exhaustiveness-unreachable-pattern.rs:63:10
9393
|
9494
LL | [1
9595
| ^
9696

9797
error: unreachable pattern
98-
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:14
98+
--> $DIR/exhaustiveness-unreachable-pattern.rs:69:14
9999
|
100100
LL | Some(0
101101
| ^
102102

103-
error: aborting due to 16 previous errors
103+
error: unreachable pattern
104+
--> $DIR/exhaustiveness-unreachable-pattern.rs:89:15
105+
|
106+
LL | | true) => {}
107+
| ^^^^
108+
109+
error: unreachable pattern
110+
--> $DIR/exhaustiveness-unreachable-pattern.rs:95:15
111+
|
112+
LL | | true,
113+
| ^^^^
114+
115+
error: aborting due to 18 previous errors
104116

src/test/ui/or-patterns/search-via-bindings.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// run-pass
44

55
#![feature(or_patterns)]
6-
#![allow(unreachable_patterns)] // FIXME(or-patterns) this shouldn't trigger
76

87
fn search(target: (bool, bool, bool)) -> u32 {
98
let x = ((false, true), (false, true), (false, true));

0 commit comments

Comments
 (0)