@@ -632,7 +632,8 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
632
632
/// empty intersection.
633
633
/// It is assumed that two spans don't overlap without one being contained in the other; in other
634
634
/// words, that the inclusion structure forms a tree and not a DAG.
635
- /// Operations on this do not need to be fast since it's only nonempty in the diagnostic path.
635
+ /// Intersection is not very efficient. It compares everything pairwise. If needed it could be made
636
+ /// faster by sorting the `Span`s and merging cleverly.
636
637
#[ derive( Debug , Clone , Default ) ]
637
638
pub ( crate ) struct SpanSet {
638
639
/// The minimal set of `Span`s required to represent the whole set. If A and B are `Span`s in
@@ -715,7 +716,7 @@ impl<'tcx> Usefulness<'tcx> {
715
716
716
717
/// When trying several branches and each returns a `Usefulness`, we need to combine the
717
718
/// results together.
718
- fn merge_or_patterns ( usefulnesses : impl Iterator < Item = ( Self , Span ) > ) -> Self {
719
+ fn merge ( usefulnesses : impl Iterator < Item = Self > ) -> Self {
719
720
// If we have detected some unreachable sub-branches, we only want to keep them when they
720
721
// were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
721
722
// in the second branch of the first or-pattern, but not otherwise. Therefore we don't want
@@ -737,62 +738,7 @@ impl<'tcx> Usefulness<'tcx> {
737
738
// ```
738
739
739
740
// Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the
740
- // sets are only non-empty in the diagnostic path.
741
- let mut unreachables: Option < SpanSet > = None ;
742
- // In case of or-patterns we don't want to intersect subpatterns that come from the first
743
- // column. Invariant: contains a list of disjoint spans.
744
- let mut unreachables_this_column = Vec :: new ( ) ;
745
-
746
- for ( u, branch_span) in usefulnesses {
747
- match u {
748
- Useful ( spans) if spans. is_empty ( ) => {
749
- // Hot path: `spans` is only non-empty in the diagnostic path.
750
- unreachables = Some ( SpanSet :: new ( ) ) ;
751
- }
752
- Useful ( spans) => {
753
- for span in spans. iter ( ) {
754
- if branch_span. contains ( span) {
755
- unreachables_this_column. push ( span)
756
- }
757
- }
758
- if let Some ( set) = & mut unreachables {
759
- if !set. is_empty ( ) {
760
- set. intersection_mut ( & spans) ;
761
- }
762
- } else {
763
- unreachables = Some ( spans) ;
764
- }
765
- }
766
- NotUseful => unreachables_this_column. push ( branch_span) ,
767
- UsefulWithWitness ( _) => {
768
- bug ! (
769
- "encountered or-pat in the expansion of `_` during exhaustiveness checking"
770
- )
771
- }
772
- }
773
- }
774
-
775
- if let Some ( mut unreachables) = unreachables {
776
- for span in unreachables_this_column {
777
- // `unreachables` contained no spans from the first column, and
778
- // `unreachables_this_column` contains only disjoint spans. Therefore it is valid
779
- // to call `push_nonintersecting`.
780
- unreachables. push_nonintersecting ( span) ;
781
- }
782
- Useful ( unreachables)
783
- } else {
784
- NotUseful
785
- }
786
- }
787
-
788
- /// When trying several branches and each returns a `Usefulness`, we need to combine the
789
- /// results together.
790
- fn merge_split_constructors ( usefulnesses : impl Iterator < Item = Self > ) -> Self {
791
- // If we have detected some unreachable sub-branches, we only want to keep them when they
792
- // were unreachable in _all_ branches. So we take a big intersection.
793
-
794
- // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the
795
- // sets are only non-empty in the diagnostic path.
741
+ // sets are only non-empty in the presence of or-patterns.
796
742
let mut unreachables: Option < SpanSet > = None ;
797
743
// Witnesses of usefulness, if any.
798
744
let mut witnesses = Vec :: new ( ) ;
@@ -831,6 +777,30 @@ impl<'tcx> Usefulness<'tcx> {
831
777
}
832
778
}
833
779
780
+ /// After calculating the usefulness for a branch of an or-pattern, call this to make this
781
+ /// usefulness mergeable with those from the other branches.
782
+ fn unsplit_or_pat ( self , this_span : Span , or_pat_spans : & [ Span ] ) -> Self {
783
+ match self {
784
+ Useful ( mut spans) => {
785
+ // We register the spans of the other branches of this or-pattern as being
786
+ // unreachable from this one. This ensures that intersecting together the sets of
787
+ // spans returns what we want.
788
+ // Until we optimize `SpanSet` however, intersecting this entails a number of
789
+ // comparisons quadratic in the number of branches.
790
+ for & span in or_pat_spans {
791
+ if span != this_span {
792
+ spans. push_nonintersecting ( span) ;
793
+ }
794
+ }
795
+ Useful ( spans)
796
+ }
797
+ x => x,
798
+ }
799
+ }
800
+
801
+ /// After calculating usefulness after a specialization, call this to recontruct a usefulness
802
+ /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
803
+ /// with the results of specializing with the other constructors.
834
804
fn apply_constructor < ' p > (
835
805
self ,
836
806
pcx : PatCtxt < ' _ , ' p , ' tcx > ,
@@ -1003,21 +973,23 @@ fn is_useful<'p, 'tcx>(
1003
973
1004
974
// If the first pattern is an or-pattern, expand it.
1005
975
let ret = if let Some ( vs) = v. expand_or_pat ( ) {
976
+ let subspans: Vec < _ > = vs. iter ( ) . map ( |v| v. head ( ) . span ) . collect ( ) ;
1006
977
// We expand the or pattern, trying each of its branches in turn and keeping careful track
1007
978
// of possible unreachable sub-branches.
1008
979
let mut matrix = matrix. clone ( ) ;
1009
980
let usefulnesses = vs. into_iter ( ) . map ( |v| {
1010
- let span = v. head ( ) . span ;
1011
- let u = is_useful ( cx, & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
981
+ let v_span = v. head ( ) . span ;
982
+ let usefulness =
983
+ is_useful ( cx, & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
1012
984
// If pattern has a guard don't add it to the matrix.
1013
985
if !is_under_guard {
1014
986
// We push the already-seen patterns into the matrix in order to detect redundant
1015
987
// branches like `Some(_) | Some(0)`.
1016
988
matrix. push ( v) ;
1017
989
}
1018
- ( u , span )
990
+ usefulness . unsplit_or_pat ( v_span , & subspans )
1019
991
} ) ;
1020
- Usefulness :: merge_or_patterns ( usefulnesses)
992
+ Usefulness :: merge ( usefulnesses)
1021
993
} else {
1022
994
// We split the head constructor of `v`.
1023
995
let ctors = v. head_ctor ( cx) . split ( pcx, Some ( hir_id) ) ;
@@ -1032,7 +1004,7 @@ fn is_useful<'p, 'tcx>(
1032
1004
is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
1033
1005
usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns)
1034
1006
} ) ;
1035
- Usefulness :: merge_split_constructors ( usefulnesses)
1007
+ Usefulness :: merge ( usefulnesses)
1036
1008
} ;
1037
1009
debug ! ( "is_useful::returns({:#?}, {:#?}) = {:?}" , matrix, v, ret) ;
1038
1010
ret
0 commit comments