Skip to content

Commit f4f20c0

Browse files
committed
Reimplement Usefulness::merge in terms of a binop
1 parent 5547105 commit f4f20c0

File tree

1 file changed

+24
-39
lines changed

1 file changed

+24
-39
lines changed

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -696,9 +696,9 @@ impl<'tcx> Usefulness<'tcx> {
696696
}
697697
}
698698

699-
/// When trying several branches and each returns a `Usefulness`, we need to combine the
700-
/// results together.
701-
fn merge(usefulnesses: impl Iterator<Item = Self>) -> Self {
699+
/// Combine usefulnesses from two branches. This is an associative operation and `NotUseful` is
700+
/// a unit.
701+
fn extend(&mut self, other: Self) {
702702
// If we have detected some unreachable sub-branches, we only want to keep them when they
703703
// were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
704704
// in the second branch of the first or-pattern, but not otherwise. Therefore we don't want
@@ -709,54 +709,39 @@ impl<'tcx> Usefulness<'tcx> {
709709
// (false | true, false | true) => {}
710710
// }
711711
// ```
712-
// Here however we _do_ want to lint that the last `false` is unreachable. So we don't want
713-
// to intersect the spans that come directly from the or-pattern, since each branch of the
714-
// or-pattern brings a new disjoint pattern.
712+
// Here however we _do_ want to lint that the last `false` is unreachable. In order to
713+
// handle that correctly, each branch of an or-pattern marks the other branches as
714+
// unreachable (see `unsplit_or_pat`). That way, intersecting the results will correctly
715+
// identify unreachable sub-patterns.
715716
// ```
716717
// match None {
717718
// Some(false) => {}
718719
// None | Some(true | false) => {}
719720
// }
720721
// ```
722+
match (&mut *self, other) {
723+
(Useful(s), Useful(o)) => s.intersection_mut(&o),
724+
(UsefulWithWitness(s), UsefulWithWitness(o)) => s.extend(o),
725+
(_, NotUseful) => {}
726+
(NotUseful, other) => *self = other,
727+
(UsefulWithWitness(_), Useful(_)) | (Useful(_), UsefulWithWitness(_)) => unreachable!(),
728+
}
729+
}
721730

722-
// Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the
723-
// sets are only non-empty in the presence of or-patterns.
724-
let mut unreachables: Option<SpanSet> = None;
725-
// Witnesses of usefulness, if any.
726-
let mut witnesses = Vec::new();
727-
731+
/// When trying several branches and each returns a `Usefulness`, we need to combine the
732+
/// results together.
733+
fn merge(usefulnesses: impl Iterator<Item = Self>) -> Self {
734+
let mut ret = NotUseful;
728735
for u in usefulnesses {
729-
match u {
730-
Useful(spans) if spans.is_empty() => {
736+
ret.extend(u);
737+
if let Useful(spans) = &ret {
738+
if spans.is_empty() {
731739
// Once we reach the empty set, more intersections won't change the result.
732-
return Useful(SpanSet::new());
733-
}
734-
Useful(spans) => {
735-
if let Some(unreachables) = &mut unreachables {
736-
if !unreachables.is_empty() {
737-
unreachables.intersection_mut(&spans);
738-
}
739-
if unreachables.is_empty() {
740-
return Useful(SpanSet::new());
741-
}
742-
} else {
743-
unreachables = Some(spans);
744-
}
745-
}
746-
NotUseful => {}
747-
UsefulWithWitness(wits) => {
748-
witnesses.extend(wits);
740+
return ret;
749741
}
750742
}
751743
}
752-
753-
if !witnesses.is_empty() {
754-
UsefulWithWitness(witnesses)
755-
} else if let Some(unreachables) = unreachables {
756-
Useful(unreachables)
757-
} else {
758-
NotUseful
759-
}
744+
ret
760745
}
761746

762747
/// After calculating the usefulness for a branch of an or-pattern, call this to make this

0 commit comments

Comments
 (0)