Skip to content

Commit de13a09

Browse files
committed
Move usefulness-specific pattern computations to usefulness
1 parent acd463f commit de13a09

File tree

2 files changed

+43
-33
lines changed

2 files changed

+43
-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<'p, 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<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
@@ -106,34 +106,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
106106
pub(crate) fn set_useful(&self) {
107107
self.useful.set(true)
108108
}
109-
pub(crate) fn is_useful(&self) -> bool {
110-
if self.useful.get() {
111-
true
112-
} else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) {
113-
// We always expand or patterns in the matrix, so we will never see the actual
114-
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
115-
// marked as useful itself, only its children will. We recover this information here.
116-
self.set_useful();
117-
true
118-
} else {
119-
false
109+
110+
/// Walk top-down and call `it` in each place where a pattern occurs
111+
/// starting with the root pattern `walk` is called on. If `it` returns
112+
/// false then we will descend no further but siblings will be processed.
113+
pub fn walk(&'p self, it: &mut impl FnMut(&'p Self) -> bool) {
114+
if !it(self) {
115+
return;
120116
}
121-
}
122117

123-
/// Report the subpatterns that were not useful, if any.
124-
pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
125-
let mut subpats = Vec::new();
126-
self.collect_redundant_subpatterns(&mut subpats);
127-
subpats
128-
}
129-
fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
130-
// We don't look at subpatterns if we already reported the whole pattern as redundant.
131-
if !self.is_useful() {
132-
subpats.push(self);
133-
} else {
134-
for p in self.iter_fields() {
135-
p.collect_redundant_subpatterns(subpats);
136-
}
118+
for p in self.iter_fields() {
119+
p.walk(it)
137120
}
138121
}
139122
}

compiler/rustc_pattern_analysis/src/usefulness.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,38 @@ pub enum Usefulness<'p, Cx: TypeCx> {
15431543
Redundant,
15441544
}
15451545

1546+
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1547+
fn collect_pattern_usefulness<'p, Cx: TypeCx>(
1548+
pat: &'p DeconstructedPat<'p, Cx>,
1549+
) -> Usefulness<'p, Cx> {
1550+
fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<'p, Cx>) -> bool {
1551+
if pat.useful.get() {
1552+
true
1553+
} else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) {
1554+
// We always expand or patterns in the matrix, so we will never see the actual
1555+
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
1556+
// marked as useful itself, only its children will. We recover this information here.
1557+
true
1558+
} else {
1559+
false
1560+
}
1561+
}
1562+
1563+
let mut subpats = Vec::new();
1564+
pat.walk(&mut |p| {
1565+
if pat_is_useful(p) {
1566+
// The pattern is useful, so we recurse to find redundant subpatterns.
1567+
true
1568+
} else {
1569+
// The pattern is redundant.
1570+
subpats.push(p);
1571+
false // stop recursing
1572+
}
1573+
});
1574+
1575+
if pat_is_useful(pat) { Usefulness::Useful(subpats) } else { Usefulness::Redundant }
1576+
}
1577+
15461578
/// The output of checking a match for exhaustiveness and arm usefulness.
15471579
pub struct UsefulnessReport<'p, Cx: TypeCx> {
15481580
/// For each arm of the input, whether that arm is useful after the arms above it.
@@ -1571,12 +1603,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
15711603
.copied()
15721604
.map(|arm| {
15731605
debug!(?arm);
1574-
// We warn when a pattern is not useful.
1575-
let usefulness = if arm.pat.is_useful() {
1576-
Usefulness::Useful(arm.pat.redundant_subpatterns())
1577-
} else {
1578-
Usefulness::Redundant
1579-
};
1606+
let usefulness = collect_pattern_usefulness(arm.pat);
15801607
(arm, usefulness)
15811608
})
15821609
.collect();

0 commit comments

Comments
 (0)