307307
308308use self :: ArmType :: * ;
309309use self :: Usefulness :: * ;
310- use super :: deconstruct_pat:: { Constructor , ConstructorSet , DeconstructedPat , WitnessPat } ;
310+ use super :: deconstruct_pat:: {
311+ Constructor , ConstructorSet , DeconstructedPat , SplitConstructorSet , WitnessPat ,
312+ } ;
311313use crate :: errors:: { NonExhaustiveOmittedPattern , Uncovered } ;
312314
313315use rustc_data_structures:: captures:: Captures ;
@@ -875,22 +877,84 @@ fn is_useful<'p, 'tcx>(
875877 ret
876878}
877879
880+ /// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
881+ /// inspect the same subvalue".
882+ /// This is used to traverse patterns column-by-column for lints. Despite similarities with
883+ /// `is_useful`, this is a different traversal. Notably this is linear in the depth of patterns,
884+ /// whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
885+ #[ derive( Debug ) ]
886+ struct PatternColumn < ' p , ' tcx > {
887+ patterns : Vec < & ' p DeconstructedPat < ' p , ' tcx > > ,
888+ }
889+
890+ impl < ' p , ' tcx > PatternColumn < ' p , ' tcx > {
891+ fn new ( patterns : Vec < & ' p DeconstructedPat < ' p , ' tcx > > ) -> Self {
892+ Self { patterns }
893+ }
894+
895+ fn is_empty ( & self ) -> bool {
896+ self . patterns . is_empty ( )
897+ }
898+ fn head_ty ( & self ) -> Option < Ty < ' tcx > > {
899+ self . patterns . get ( 0 ) . map ( |p| p. ty ( ) )
900+ }
901+
902+ fn analyze_ctors ( & self , pcx : & PatCtxt < ' _ , ' p , ' tcx > ) -> SplitConstructorSet < ' tcx > {
903+ let column_ctors = self . patterns . iter ( ) . map ( |p| p. ctor ( ) ) ;
904+ ConstructorSet :: for_ty ( pcx. cx , pcx. ty ) . split ( pcx, column_ctors)
905+ }
906+
907+ /// Does specialization: given a constructor, this takes the patterns from the column that match
908+ /// the constructor, and outputs their fields.
909+ /// This returns one column per field of the constructor. The normally all have the same length
910+ /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns
911+ /// which may change the lengths.
912+ fn specialize ( & self , pcx : & PatCtxt < ' _ , ' p , ' tcx > , ctor : & Constructor < ' tcx > ) -> Vec < Self > {
913+ let arity = ctor. arity ( pcx) ;
914+ if arity == 0 {
915+ return Vec :: new ( ) ;
916+ }
917+
918+ // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
919+ // columns may have different lengths in the presence of or-patterns (this is why we can't
920+ // reuse `Matrix`).
921+ let mut specialized_columns: Vec < _ > =
922+ ( 0 ..arity) . map ( |_| Self { patterns : Vec :: new ( ) } ) . collect ( ) ;
923+ let relevant_patterns =
924+ self . patterns . iter ( ) . filter ( |pat| ctor. is_covered_by ( pcx, pat. ctor ( ) ) ) ;
925+ for pat in relevant_patterns {
926+ let specialized = pat. specialize ( pcx, & ctor) ;
927+ for ( subpat, column) in specialized. iter ( ) . zip ( & mut specialized_columns) {
928+ if subpat. is_or_pat ( ) {
929+ column. patterns . extend ( subpat. iter_fields ( ) )
930+ } else {
931+ column. patterns . push ( subpat)
932+ }
933+ }
934+ }
935+
936+ assert ! (
937+ !specialized_columns[ 0 ] . is_empty( ) ,
938+ "ctor {ctor:?} was listed as present but isn't;
939+ there is an inconsistency between `Constructor::is_covered_by` and `ConstructorSet::split`"
940+ ) ;
941+ specialized_columns
942+ }
943+ }
944+
878945/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
879- /// in a given column. This traverses patterns column-by-column, where a column is the intuitive
880- /// notion of "subpatterns that inspect the same subvalue".
881- /// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the
882- /// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
946+ /// in a given column.
947+ #[ instrument( level = "debug" , skip( cx) , ret) ]
883948fn collect_nonexhaustive_missing_variants < ' p , ' tcx > (
884949 cx : & MatchCheckCtxt < ' p , ' tcx > ,
885- column : & [ & DeconstructedPat < ' p , ' tcx > ] ,
950+ column : & PatternColumn < ' p , ' tcx > ,
886951) -> Vec < WitnessPat < ' tcx > > {
887- if column. is_empty ( ) {
952+ let Some ( ty ) = column. head_ty ( ) else {
888953 return Vec :: new ( ) ;
889- }
890- let ty = column[ 0 ] . ty ( ) ;
954+ } ;
891955 let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level : false } ;
892956
893- let set = ConstructorSet :: for_ty ( pcx . cx , pcx . ty ) . split ( pcx , column. iter ( ) . map ( |p| p . ctor ( ) ) ) ;
957+ let set = column. analyze_ctors ( pcx ) ;
894958 if set. present . is_empty ( ) {
895959 // We can't consistently handle the case where no constructors are present (since this would
896960 // require digging deep through any type in case there's a non_exhaustive enum somewhere),
@@ -911,35 +975,11 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
911975
912976 // Recurse into the fields.
913977 for ctor in set. present {
914- let arity = ctor. arity ( pcx) ;
915- if arity == 0 {
916- continue ;
917- }
918-
919- // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
920- // columns may have different lengths in the presence of or-patterns (this is why we can't
921- // reuse `Matrix`).
922- let mut specialized_columns: Vec < Vec < _ > > = ( 0 ..arity) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
923- let relevant_patterns = column. iter ( ) . filter ( |pat| ctor. is_covered_by ( pcx, pat. ctor ( ) ) ) ;
924- for pat in relevant_patterns {
925- let specialized = pat. specialize ( pcx, & ctor) ;
926- for ( subpat, sub_column) in specialized. iter ( ) . zip ( & mut specialized_columns) {
927- if subpat. is_or_pat ( ) {
928- sub_column. extend ( subpat. iter_fields ( ) )
929- } else {
930- sub_column. push ( subpat)
931- }
932- }
933- }
934- debug_assert ! (
935- !specialized_columns[ 0 ] . is_empty( ) ,
936- "ctor {ctor:?} was listed as present but isn't"
937- ) ;
938-
978+ let specialized_columns = column. specialize ( pcx, & ctor) ;
939979 let wild_pat = WitnessPat :: wild_from_ctor ( pcx, ctor) ;
940980 for ( i, col_i) in specialized_columns. iter ( ) . enumerate ( ) {
941981 // Compute witnesses for each column.
942- let wits_for_col_i = collect_nonexhaustive_missing_variants ( cx, col_i. as_slice ( ) ) ;
982+ let wits_for_col_i = collect_nonexhaustive_missing_variants ( cx, col_i) ;
943983 // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
944984 // adding enough wildcards to match `arity`.
945985 for wit in wits_for_col_i {
@@ -1032,6 +1072,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
10321072 )
10331073 {
10341074 let pat_column = arms. iter ( ) . flat_map ( |arm| arm. pat . flatten_or_pat ( ) ) . collect :: < Vec < _ > > ( ) ;
1075+ let pat_column = PatternColumn :: new ( pat_column) ;
10351076 let witnesses = collect_nonexhaustive_missing_variants ( cx, & pat_column) ;
10361077
10371078 if !witnesses. is_empty ( ) {
0 commit comments