@@ -648,6 +648,81 @@ impl<'tcx> Usefulness<'tcx> {
648648 !matches ! ( * self , NotUseful )
649649 }
650650
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+
651726 fn apply_constructor < ' p > (
652727 self ,
653728 pcx : PatCtxt < ' _ , ' p , ' tcx > ,
@@ -833,85 +908,19 @@ fn is_useful<'p, 'tcx>(
833908 if let Some ( vs) = v. expand_or_pat ( ) {
834909 // We expand the or pattern, trying each of its branches in turn and keeping careful track
835910 // 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-
859911 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 ) ;
895915 // If pattern has a guard don't add it to the matrix.
896916 if !is_under_guard {
897917 // We push the already-seen patterns into the matrix in order to detect redundant
898918 // branches like `Some(_) | Some(0)`.
899919 matrix. push ( v) ;
900920 }
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 ( ) ) ;
915924 }
916925
917926 // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
0 commit comments