Skip to content

Commit

Permalink
Move usefulness-specific pattern computations to usefulness
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Feb 7, 2024
1 parent 586893c commit dcda83f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 33 deletions.
37 changes: 10 additions & 27 deletions compiler/rustc_pattern_analysis/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct DeconstructedPat<Cx: TypeCx> {
/// correspond to a user-supplied pattern.
data: Option<Cx::PatData>,
/// Whether removing this arm would change the behavior of the match expression.
useful: Cell<bool>,
pub(crate) useful: Cell<bool>,
}

impl<Cx: TypeCx> DeconstructedPat<Cx> {
Expand Down Expand Up @@ -112,34 +112,17 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
pub(crate) fn set_useful(&self) {
self.useful.set(true)
}
pub(crate) fn is_useful(&self) -> bool {
if self.useful.get() {
true
} else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) {
// We always expand or patterns in the matrix, so we will never see the actual
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
// marked as useful itself, only its children will. We recover this information here.
self.set_useful();
true
} else {
false

/// Walk top-down and call `it` in each place where a pattern occurs
/// starting with the root pattern `walk` is called on. If `it` returns
/// false then we will descend no further but siblings will be processed.
pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) {
if !it(self) {
return;
}
}

/// Report the subpatterns that were not useful, if any.
pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> {
let mut subpats = Vec::new();
self.collect_redundant_subpatterns(&mut subpats);
subpats
}
fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) {
// We don't look at subpatterns if we already reported the whole pattern as redundant.
if !self.is_useful() {
subpats.push(self);
} else {
for p in self.iter_fields() {
p.collect_redundant_subpatterns(subpats);
}
for p in self.iter_fields() {
p.walk(it)
}
}
}
Expand Down
37 changes: 31 additions & 6 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,36 @@ pub enum Usefulness<'p, Cx: TypeCx> {
Redundant,
}

/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> Usefulness<'p, Cx> {
fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) -> bool {
if pat.useful.get() {
true
} else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) {
// We always expand or patterns in the matrix, so we will never see the actual
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
// marked as useful itself, only its children will. We recover this information here.
true
} else {
false
}
}

let mut subpats = Vec::new();
pat.walk(&mut |p| {
if pat_is_useful(p) {
// The pattern is useful, so we recurse to find redundant subpatterns.
true
} else {
// The pattern is redundant.
subpats.push(p);
false // stop recursing
}
});

if pat_is_useful(pat) { Usefulness::Useful(subpats) } else { Usefulness::Redundant }
}

/// The output of checking a match for exhaustiveness and arm usefulness.
pub struct UsefulnessReport<'p, Cx: TypeCx> {
/// For each arm of the input, whether that arm is useful after the arms above it.
Expand Down Expand Up @@ -1609,12 +1639,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
.copied()
.map(|arm| {
debug!(?arm);
// We warn when a pattern is not useful.
let usefulness = if arm.pat.is_useful() {
Usefulness::Useful(arm.pat.redundant_subpatterns())
} else {
Usefulness::Redundant
};
let usefulness = collect_pattern_usefulness(arm.pat);
(arm, usefulness)
})
.collect();
Expand Down

0 comments on commit dcda83f

Please sign in to comment.