Skip to content

Commit cb3ce66

Browse files
committed
Move usefulness-specific pattern computations to usefulness
1 parent 8ace7ea commit cb3ce66

File tree

2 files changed

+41
-33
lines changed

2 files changed

+41
-33
lines changed

compiler/rustc_pattern_analysis/src/pat.rs

+10-27
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct DeconstructedPat<Cx: TypeCx> {
2929
/// correspond to a user-supplied pattern.
3030
data: Option<Cx::PatData>,
3131
/// Whether removing this arm would change the behavior of the match expression.
32-
useful: Cell<bool>,
32+
pub(crate) useful: Cell<bool>,
3333
}
3434

3535
impl<Cx: TypeCx> DeconstructedPat<Cx> {
@@ -112,34 +112,17 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
112112
pub(crate) fn set_useful(&self) {
113113
self.useful.set(true)
114114
}
115-
pub(crate) fn is_useful(&self) -> bool {
116-
if self.useful.get() {
117-
true
118-
} else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) {
119-
// We always expand or patterns in the matrix, so we will never see the actual
120-
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
121-
// marked as useful itself, only its children will. We recover this information here.
122-
self.set_useful();
123-
true
124-
} else {
125-
false
115+
116+
/// Walk top-down and call `it` in each place where a pattern occurs
117+
/// starting with the root pattern `walk` is called on. If `it` returns
118+
/// false then we will descend no further but siblings will be processed.
119+
pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) {
120+
if !it(self) {
121+
return;
126122
}
127-
}
128123

129-
/// Report the subpatterns that were not useful, if any.
130-
pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
131-
let mut subpats = Vec::new();
132-
self.collect_redundant_subpatterns(&mut subpats);
133-
subpats
134-
}
135-
fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
136-
// We don't look at subpatterns if we already reported the whole pattern as redundant.
137-
if !self.is_useful() {
138-
subpats.push(self);
139-
} else {
140-
for p in self.iter_fields() {
141-
p.collect_redundant_subpatterns(subpats);
142-
}
124+
for p in self.iter_fields() {
125+
p.walk(it)
143126
}
144127
}
145128
}

compiler/rustc_pattern_analysis/src/usefulness.rs

+31-6
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,36 @@ pub enum Usefulness<'p, Cx: TypeCx> {
15991599
Redundant,
16001600
}
16011601

1602+
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1603+
fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> Usefulness<'p, Cx> {
1604+
fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> bool {
1605+
if pat.useful.get() {
1606+
true
1607+
} else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) {
1608+
// We always expand or patterns in the matrix, so we will never see the actual
1609+
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
1610+
// marked as useful itself, only its children will. We recover this information here.
1611+
true
1612+
} else {
1613+
false
1614+
}
1615+
}
1616+
1617+
let mut redundant_subpats = Vec::new();
1618+
pat.walk(&mut |p| {
1619+
if pat_is_useful(p) {
1620+
// The pattern is useful, so we recurse to find redundant subpatterns.
1621+
true
1622+
} else {
1623+
// The pattern is redundant.
1624+
redundant_subpats.push(p);
1625+
false // stop recursing
1626+
}
1627+
});
1628+
1629+
if pat_is_useful(pat) { Usefulness::Useful(redundant_subpats) } else { Usefulness::Redundant }
1630+
}
1631+
16021632
/// The output of checking a match for exhaustiveness and arm usefulness.
16031633
pub struct UsefulnessReport<'p, Cx: TypeCx> {
16041634
/// For each arm of the input, whether that arm is useful after the arms above it.
@@ -1626,12 +1656,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
16261656
.copied()
16271657
.map(|arm| {
16281658
debug!(?arm);
1629-
// We warn when a pattern is not useful.
1630-
let usefulness = if arm.pat.is_useful() {
1631-
Usefulness::Useful(arm.pat.redundant_subpatterns())
1632-
} else {
1633-
Usefulness::Redundant
1634-
};
1659+
let usefulness = collect_pattern_usefulness(arm.pat);
16351660
(arm, usefulness)
16361661
})
16371662
.collect();

0 commit comments

Comments
 (0)