Skip to content

Commit cc3b75a

Browse files
authored
Rollup merge of rust-lang#66967 - Nadrieril:remove-or-pat-hack, r=varkor
Remove hack for top-level or-patterns in match checking Follow-up to rust-lang#66612. Or-patterns are now truly first-class in match checking. As a side-effect, redundant subpatterns are linted as such, making the `unreachable_patterns` lint a bit more general. cc rust-lang#54883 r? @varkor
2 parents 29e5b0a + 1c1bec2 commit cc3b75a

File tree

7 files changed

+355
-177
lines changed

7 files changed

+355
-177
lines changed

src/librustc_mir/hair/pattern/_match.rs

+56-49
Original file line numberDiff line numberDiff line change
@@ -425,16 +425,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
425425
}
426426

427427
/// This computes `S(constructor, self)`. See top of the file for explanations.
428-
fn specialize_constructor<'a, 'q>(
428+
fn specialize_constructor(
429429
&self,
430-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
430+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
431431
constructor: &Constructor<'tcx>,
432-
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
433-
) -> Option<PatStack<'q, 'tcx>>
434-
where
435-
'a: 'q,
436-
'p: 'q,
437-
{
432+
ctor_wild_subpatterns: &'p [Pat<'tcx>],
433+
) -> Option<PatStack<'p, 'tcx>> {
438434
let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
439435
new_heads.map(|mut new_head| {
440436
new_head.0.extend_from_slice(&self.0[1..]);
@@ -459,6 +455,7 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
459455
}
460456

461457
/// A 2D matrix.
458+
#[derive(Clone)]
462459
pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
463460

464461
impl<'p, 'tcx> Matrix<'p, 'tcx> {
@@ -486,16 +483,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
486483
}
487484

488485
/// This computes `S(constructor, self)`. See top of the file for explanations.
489-
fn specialize_constructor<'a, 'q>(
486+
fn specialize_constructor(
490487
&self,
491-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
488+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
492489
constructor: &Constructor<'tcx>,
493-
ctor_wild_subpatterns: &[&'q Pat<'tcx>],
494-
) -> Matrix<'q, 'tcx>
495-
where
496-
'a: 'q,
497-
'p: 'q,
498-
{
490+
ctor_wild_subpatterns: &'p [Pat<'tcx>],
491+
) -> Matrix<'p, 'tcx> {
499492
self.0
500493
.iter()
501494
.filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
@@ -1033,17 +1026,19 @@ impl<'tcx> Constructor<'tcx> {
10331026
}
10341027

10351028
#[derive(Clone, Debug)]
1036-
pub enum Usefulness<'tcx> {
1037-
Useful,
1029+
pub enum Usefulness<'tcx, 'p> {
1030+
/// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
1031+
Useful(Vec<&'p Pat<'tcx>>),
1032+
/// Carries a list of witnesses of non-exhaustiveness.
10381033
UsefulWithWitness(Vec<Witness<'tcx>>),
10391034
NotUseful,
10401035
}
10411036

1042-
impl<'tcx> Usefulness<'tcx> {
1037+
impl<'tcx, 'p> Usefulness<'tcx, 'p> {
10431038
fn new_useful(preference: WitnessPreference) -> Self {
10441039
match preference {
10451040
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
1046-
LeaveOutWitness => Useful,
1041+
LeaveOutWitness => Useful(vec![]),
10471042
}
10481043
}
10491044

@@ -1604,13 +1599,13 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
16041599
/// relation to preceding patterns, it is not reachable) and exhaustiveness
16051600
/// checking (if a wildcard pattern is useful in relation to a matrix, the
16061601
/// matrix isn't exhaustive).
1607-
pub fn is_useful<'p, 'a, 'tcx>(
1608-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
1602+
pub fn is_useful<'p, 'tcx>(
1603+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
16091604
matrix: &Matrix<'p, 'tcx>,
1610-
v: &PatStack<'_, 'tcx>,
1605+
v: &PatStack<'p, 'tcx>,
16111606
witness_preference: WitnessPreference,
16121607
hir_id: HirId,
1613-
) -> Usefulness<'tcx> {
1608+
) -> Usefulness<'tcx, 'p> {
16141609
let &Matrix(ref rows) = matrix;
16151610
debug!("is_useful({:#?}, {:#?})", matrix, v);
16161611

@@ -1631,11 +1626,26 @@ pub fn is_useful<'p, 'a, 'tcx>(
16311626

16321627
// If the first pattern is an or-pattern, expand it.
16331628
if let Some(vs) = v.expand_or_pat() {
1634-
return vs
1635-
.into_iter()
1636-
.map(|v| is_useful(cx, matrix, &v, witness_preference, hir_id))
1637-
.find(|result| result.is_useful())
1638-
.unwrap_or(NotUseful);
1629+
// We need to push the already-seen patterns into the matrix in order to detect redundant
1630+
// branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
1631+
let mut matrix = matrix.clone();
1632+
let mut unreachable_pats = Vec::new();
1633+
let mut any_is_useful = false;
1634+
for v in vs {
1635+
let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
1636+
match res {
1637+
Useful(pats) => {
1638+
any_is_useful = true;
1639+
unreachable_pats.extend(pats);
1640+
}
1641+
NotUseful => unreachable_pats.push(v.head()),
1642+
UsefulWithWitness(_) => {
1643+
bug!("Encountered or-pat in `v` during exhaustiveness checking")
1644+
}
1645+
}
1646+
matrix.push(v);
1647+
}
1648+
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
16391649
}
16401650

16411651
let (ty, span) = matrix
@@ -1768,21 +1778,21 @@ pub fn is_useful<'p, 'a, 'tcx>(
17681778

17691779
/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
17701780
/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
1771-
fn is_useful_specialized<'p, 'a, 'tcx>(
1772-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
1781+
fn is_useful_specialized<'p, 'tcx>(
1782+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
17731783
matrix: &Matrix<'p, 'tcx>,
1774-
v: &PatStack<'_, 'tcx>,
1784+
v: &PatStack<'p, 'tcx>,
17751785
ctor: Constructor<'tcx>,
17761786
lty: Ty<'tcx>,
17771787
witness_preference: WitnessPreference,
17781788
hir_id: HirId,
1779-
) -> Usefulness<'tcx> {
1789+
) -> Usefulness<'tcx, 'p> {
17801790
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
17811791

1782-
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty);
1783-
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
1784-
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
1785-
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
1792+
let ctor_wild_subpatterns =
1793+
cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
1794+
let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
1795+
v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
17861796
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
17871797
.map(|u| u.apply_constructor(cx, &ctor, lty))
17881798
.unwrap_or(NotUseful)
@@ -2250,13 +2260,13 @@ fn constructor_covered_by_range<'tcx>(
22502260
if intersects { Some(()) } else { None }
22512261
}
22522262

2253-
fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
2254-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
2263+
fn patterns_for_variant<'p, 'tcx>(
2264+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
22552265
subpatterns: &'p [FieldPat<'tcx>],
2256-
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
2266+
ctor_wild_subpatterns: &'p [Pat<'tcx>],
22572267
is_non_exhaustive: bool,
22582268
) -> PatStack<'p, 'tcx> {
2259-
let mut result = SmallVec::from_slice(ctor_wild_subpatterns);
2269+
let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
22602270

22612271
for subpat in subpatterns {
22622272
if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
@@ -2280,11 +2290,11 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
22802290
/// different patterns.
22812291
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
22822292
/// fields filled with wild patterns.
2283-
fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
2284-
cx: &mut MatchCheckCtxt<'a, 'tcx>,
2285-
pat: &'q Pat<'tcx>,
2293+
fn specialize_one_pattern<'p, 'tcx>(
2294+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
2295+
pat: &'p Pat<'tcx>,
22862296
constructor: &Constructor<'tcx>,
2287-
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
2297+
ctor_wild_subpatterns: &'p [Pat<'tcx>],
22882298
) -> Option<PatStack<'p, 'tcx>> {
22892299
if let NonExhaustive = constructor {
22902300
// Only a wildcard pattern can match the special extra constructor
@@ -2294,9 +2304,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
22942304
let result = match *pat.kind {
22952305
PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
22962306

2297-
PatKind::Binding { .. } | PatKind::Wild => {
2298-
Some(PatStack::from_slice(ctor_wild_subpatterns))
2299-
}
2307+
PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
23002308

23012309
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
23022310
let ref variant = adt_def.variants[variant_index];
@@ -2406,7 +2414,6 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
24062414
.chain(
24072415
ctor_wild_subpatterns
24082416
.iter()
2409-
.map(|p| *p)
24102417
.skip(prefix.len())
24112418
.take(slice_count)
24122419
.chain(suffix.iter()),

0 commit comments

Comments
 (0)