@@ -648,6 +648,81 @@ impl<'tcx> Usefulness<'tcx> {
648
648
!matches ! ( * self , NotUseful )
649
649
}
650
650
651
+ /// When trying several branches and each returns a `Usefulness`, we need to combine the
652
+ /// results together.
653
+ fn merge ( usefulnesses : impl Iterator < Item = ( Self , Span ) > , column_count : usize ) -> Self {
654
+ // If two branches have detected some unreachable sub-branches, we need to be careful. If
655
+ // they were detected in columns that are not the current one, we want to keep only the
656
+ // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
657
+ // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
658
+ // Therefore we don't want to lint that it is unreachable.
659
+ //
660
+ // ```
661
+ // match (true, true) {
662
+ // (true, true) => {}
663
+ // (false | true, false | true) => {}
664
+ // }
665
+ // ```
666
+ // If however the sub-branches come from the current column, they come from the inside of
667
+ // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
668
+ // to lint that the last `false` is unreachable.
669
+ // ```
670
+ // match None {
671
+ // Some(false) => {}
672
+ // None | Some(true | false) => {}
673
+ // }
674
+ // ```
675
+
676
+ // We keep track of sub-branches separately depending on whether they come from this column
677
+ // or from others.
678
+ let mut unreachables_this_column: FxHashSet < Span > = FxHashSet :: default ( ) ;
679
+ let mut unreachables_other_columns: Vec < FxHashSet < Span > > = Vec :: default ( ) ;
680
+ // Whether at least one branch is reachable.
681
+ let mut any_is_useful = false ;
682
+
683
+ for ( u, span) in usefulnesses {
684
+ match u {
685
+ Useful ( unreachables) => {
686
+ if let Some ( ( this_column, other_columns) ) = unreachables. split_last ( ) {
687
+ // We keep the union of unreachables found in the first column.
688
+ unreachables_this_column. extend ( this_column) ;
689
+ // We keep the intersection of unreachables found in other columns.
690
+ if unreachables_other_columns. is_empty ( ) {
691
+ unreachables_other_columns = other_columns. to_vec ( ) ;
692
+ } else {
693
+ unreachables_other_columns = unreachables_other_columns
694
+ . into_iter ( )
695
+ . zip ( other_columns)
696
+ . map ( |( x, y) | x. intersection ( & y) . copied ( ) . collect ( ) )
697
+ . collect ( ) ;
698
+ }
699
+ }
700
+ any_is_useful = true ;
701
+ }
702
+ NotUseful => {
703
+ unreachables_this_column. insert ( span) ;
704
+ }
705
+ UsefulWithWitness ( _) => {
706
+ bug ! (
707
+ "encountered or-pat in the expansion of `_` during exhaustiveness checking"
708
+ )
709
+ }
710
+ }
711
+ }
712
+
713
+ if any_is_useful {
714
+ let mut unreachables = if unreachables_other_columns. is_empty ( ) {
715
+ ( 0 ..column_count - 1 ) . map ( |_| FxHashSet :: default ( ) ) . collect ( )
716
+ } else {
717
+ unreachables_other_columns
718
+ } ;
719
+ unreachables. push ( unreachables_this_column) ;
720
+ Useful ( unreachables)
721
+ } else {
722
+ NotUseful
723
+ }
724
+ }
725
+
651
726
fn apply_constructor < ' p > (
652
727
self ,
653
728
pcx : PatCtxt < ' _ , ' p , ' tcx > ,
@@ -833,85 +908,19 @@ fn is_useful<'p, 'tcx>(
833
908
if let Some ( vs) = v. expand_or_pat ( ) {
834
909
// We expand the or pattern, trying each of its branches in turn and keeping careful track
835
910
// of possible unreachable sub-branches.
836
- //
837
- // If two branches have detected some unreachable sub-branches, we need to be careful. If
838
- // they were detected in columns that are not the current one, we want to keep only the
839
- // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
840
- // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
841
- // Therefore we don't want to lint that it is unreachable.
842
- //
843
- // ```
844
- // match (true, true) {
845
- // (true, true) => {}
846
- // (false | true, false | true) => {}
847
- // }
848
- // ```
849
- // If however the sub-branches come from the current column, they come from the inside of
850
- // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
851
- // to lint that the last `false` is unreachable.
852
- // ```
853
- // match None {
854
- // Some(false) => {}
855
- // None | Some(true | false) => {}
856
- // }
857
- // ```
858
-
859
911
let mut matrix = matrix. clone ( ) ;
860
- // We keep track of sub-branches separately depending on whether they come from this column
861
- // or from others.
862
- let mut unreachables_this_column: FxHashSet < Span > = FxHashSet :: default ( ) ;
863
- let mut unreachables_other_columns: Vec < FxHashSet < Span > > = Vec :: default ( ) ;
864
- // Whether at least one branch is reachable.
865
- let mut any_is_useful = false ;
866
-
867
- for v in vs {
868
- let res = is_useful ( cx, & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
869
- match res {
870
- Useful ( unreachables) => {
871
- if let Some ( ( this_column, other_columns) ) = unreachables. split_last ( ) {
872
- // We keep the union of unreachables found in the first column.
873
- unreachables_this_column. extend ( this_column) ;
874
- // We keep the intersection of unreachables found in other columns.
875
- if unreachables_other_columns. is_empty ( ) {
876
- unreachables_other_columns = other_columns. to_vec ( ) ;
877
- } else {
878
- unreachables_other_columns = unreachables_other_columns
879
- . into_iter ( )
880
- . zip ( other_columns)
881
- . map ( |( x, y) | x. intersection ( & y) . copied ( ) . collect ( ) )
882
- . collect ( ) ;
883
- }
884
- }
885
- any_is_useful = true ;
886
- }
887
- NotUseful => {
888
- unreachables_this_column. insert ( v. head ( ) . span ) ;
889
- }
890
- UsefulWithWitness ( _) => bug ! (
891
- "encountered or-pat in the expansion of `_` during exhaustiveness checking"
892
- ) ,
893
- }
894
-
912
+ let usefulnesses = vs. into_iter ( ) . map ( |v| {
913
+ let span = v. head ( ) . span ;
914
+ let u = is_useful ( cx, & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
895
915
// If pattern has a guard don't add it to the matrix.
896
916
if !is_under_guard {
897
917
// We push the already-seen patterns into the matrix in order to detect redundant
898
918
// branches like `Some(_) | Some(0)`.
899
919
matrix. push ( v) ;
900
920
}
901
- }
902
-
903
- return if any_is_useful {
904
- let mut unreachables = if unreachables_other_columns. is_empty ( ) {
905
- let n_columns = v. len ( ) ;
906
- ( 0 ..n_columns - 1 ) . map ( |_| FxHashSet :: default ( ) ) . collect ( )
907
- } else {
908
- unreachables_other_columns
909
- } ;
910
- unreachables. push ( unreachables_this_column) ;
911
- Useful ( unreachables)
912
- } else {
913
- NotUseful
914
- } ;
921
+ ( u, span)
922
+ } ) ;
923
+ return Usefulness :: merge ( usefulnesses, v. len ( ) ) ;
915
924
}
916
925
917
926
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
0 commit comments