11use  rustc_session:: lint:: builtin:: NON_EXHAUSTIVE_OMITTED_PATTERNS ; 
22use  rustc_span:: ErrorGuaranteed ; 
33
4+ use  crate :: constructor:: Constructor ; 
45use  crate :: errors:: { NonExhaustiveOmittedPattern ,  NonExhaustiveOmittedPatternLintOnArm ,  Uncovered } ; 
5- use  crate :: pat:: PatOrWild ; 
6- use  crate :: rustc:: { 
7-     Constructor ,  DeconstructedPat ,  MatchArm ,  MatchCtxt ,  PlaceCtxt ,  RevealedTy ,  RustcMatchCheckCtxt , 
8-     SplitConstructorSet ,  WitnessPat , 
9- } ; 
10- 
11- /// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that 
12- /// inspect the same subvalue/place". 
13- /// This is used to traverse patterns column-by-column for lints. Despite similarities with the 
14- /// algorithm in [`crate::usefulness`], this does a different traversal. Notably this is linear in 
15- /// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential 
16- /// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately. 
17- /// 
18- /// This must not contain an or-pattern. `expand_and_push` takes care to expand them. 
19- /// 
20- /// This is not used in the usefulness algorithm; only in lints. 
21- #[ derive( Debug ) ]  
22- pub ( crate )  struct  PatternColumn < ' p ,  ' tcx >  { 
23-     patterns :  Vec < & ' p  DeconstructedPat < ' p ,  ' tcx > > , 
24- } 
25- 
26- impl < ' p ,  ' tcx >  PatternColumn < ' p ,  ' tcx >  { 
27-     pub ( crate )  fn  new ( arms :  & [ MatchArm < ' p ,  ' tcx > ] )  -> Self  { 
28-         let  patterns = Vec :: with_capacity ( arms. len ( ) ) ; 
29-         let  mut  column = PatternColumn  {  patterns } ; 
30-         for  arm in  arms { 
31-             column. expand_and_push ( PatOrWild :: Pat ( arm. pat ) ) ; 
32-         } 
33-         column
34-     } 
35-     /// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns. 
36- /// Internal method, prefer [`PatternColumn::new`]. 
37- fn  expand_and_push ( & mut  self ,  pat :  PatOrWild < ' p ,  RustcMatchCheckCtxt < ' p ,  ' tcx > > )  { 
38-         // We flatten or-patterns and skip algorithm-generated wildcards. 
39-         if  pat. is_or_pat ( )  { 
40-             self . patterns . extend ( 
41-                 pat. flatten_or_pat ( ) . into_iter ( ) . filter_map ( |pat_or_wild| pat_or_wild. as_pat ( ) ) , 
42-             ) 
43-         }  else  if  let  Some ( pat)  = pat. as_pat ( )  { 
44-             self . patterns . push ( pat) 
45-         } 
46-     } 
47- 
48-     fn  head_ty ( & self )  -> Option < RevealedTy < ' tcx > >  { 
49-         self . patterns . first ( ) . map ( |pat| * pat. ty ( ) ) 
50-     } 
51- 
52-     /// Do constructor splitting on the constructors of the column. 
53- fn  analyze_ctors ( 
54-         & self , 
55-         pcx :  & PlaceCtxt < ' _ ,  ' p ,  ' tcx > , 
56-     )  -> Result < SplitConstructorSet < ' p ,  ' tcx > ,  ErrorGuaranteed >  { 
57-         let  column_ctors = self . patterns . iter ( ) . map ( |p| p. ctor ( ) ) ; 
58-         let  ctors_for_ty = & pcx. ctors_for_ty ( ) ?; 
59-         Ok ( ctors_for_ty. split ( column_ctors) ) 
60-     } 
61- 
62-     /// Does specialization: given a constructor, this takes the patterns from the column that match 
63- /// the constructor, and outputs their fields. 
64- /// This returns one column per field of the constructor. They usually all have the same length 
65- /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns 
66- /// which may change the lengths. 
67- fn  specialize ( 
68-         & self , 
69-         pcx :  & PlaceCtxt < ' _ ,  ' p ,  ' tcx > , 
70-         ctor :  & Constructor < ' p ,  ' tcx > , 
71-     )  -> Vec < PatternColumn < ' p ,  ' tcx > >  { 
72-         let  arity = ctor. arity ( pcx) ; 
73-         if  arity == 0  { 
74-             return  Vec :: new ( ) ; 
75-         } 
76- 
77-         // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These 
78-         // columns may have different lengths in the presence of or-patterns (this is why we can't 
79-         // reuse `Matrix`). 
80-         let  mut  specialized_columns:  Vec < _ >  =
81-             ( 0 ..arity) . map ( |_| Self  {  patterns :  Vec :: new ( )  } ) . collect ( ) ; 
82-         let  relevant_patterns =
83-             self . patterns . iter ( ) . filter ( |pat| ctor. is_covered_by ( pcx,  pat. ctor ( ) ) ) ; 
84-         for  pat in  relevant_patterns { 
85-             let  specialized = pat. specialize ( ctor,  arity) ; 
86-             for  ( subpat,  column)  in  specialized. into_iter ( ) . zip ( & mut  specialized_columns)  { 
87-                 column. expand_and_push ( subpat) ; 
88-             } 
89-         } 
90-         specialized_columns
91-     } 
92- } 
6+ use  crate :: pat_column:: PatternColumn ; 
7+ use  crate :: rustc:: { RevealedTy ,  RustcMatchCheckCtxt ,  WitnessPat } ; 
8+ use  crate :: MatchArm ; 
939
9410/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned 
9511/// in a given column. 
9612#[ instrument( level = "debug" ,  skip( cx) ,  ret) ]  
9713fn  collect_nonexhaustive_missing_variants < ' a ,  ' p ,  ' tcx > ( 
98-     cx :  MatchCtxt < ' a ,   ' p ,  ' tcx > , 
99-     column :  & PatternColumn < ' p ,  ' tcx > , 
14+     cx :  & RustcMatchCheckCtxt < ' p ,  ' tcx > , 
15+     column :  & PatternColumn < ' p ,  RustcMatchCheckCtxt < ' p ,   ' tcx > > , 
10016)  -> Result < Vec < WitnessPat < ' p ,  ' tcx > > ,  ErrorGuaranteed >  { 
101-     let  Some ( ty)  = column. head_ty ( )  else  { 
17+     let  Some ( & ty)  = column. head_ty ( )  else  { 
10218        return  Ok ( Vec :: new ( ) ) ; 
10319    } ; 
104-     let  pcx = & PlaceCtxt :: new_dummy ( cx,  & ty) ; 
10520
106-     let  set = column. analyze_ctors ( pcx ) ?; 
21+     let  set = column. analyze_ctors ( cx ,   & ty ) ?; 
10722    if  set. present . is_empty ( )  { 
10823        // We can't consistently handle the case where no constructors are present (since this would 
10924        // require digging deep through any type in case there's a non_exhaustive enum somewhere), 
@@ -112,20 +27,20 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
11227    } 
11328
11429    let  mut  witnesses = Vec :: new ( ) ; 
115-     if  cx. tycx . is_foreign_non_exhaustive_enum ( ty)  { 
30+     if  cx. is_foreign_non_exhaustive_enum ( ty)  { 
11631        witnesses. extend ( 
11732            set. missing 
11833                . into_iter ( ) 
11934                // This will list missing visible variants. 
12035                . filter ( |c| !matches ! ( c,  Constructor :: Hidden  | Constructor :: NonExhaustive ) ) 
121-                 . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( pcx ,  missing_ctor) ) , 
36+                 . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( cx ,  missing_ctor,  ty ) ) , 
12237        ) 
12338    } 
12439
12540    // Recurse into the fields. 
12641    for  ctor in  set. present  { 
127-         let  specialized_columns = column. specialize ( pcx ,  & ctor) ; 
128-         let  wild_pat = WitnessPat :: wild_from_ctor ( pcx ,  ctor) ; 
42+         let  specialized_columns = column. specialize ( cx ,   & ty ,  & ctor) ; 
43+         let  wild_pat = WitnessPat :: wild_from_ctor ( cx ,  ctor,  ty ) ; 
12944        for  ( i,  col_i)  in  specialized_columns. iter ( ) . enumerate ( )  { 
13045            // Compute witnesses for each column. 
13146            let  wits_for_col_i = collect_nonexhaustive_missing_variants ( cx,  col_i) ?; 
@@ -141,18 +56,17 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
14156    Ok ( witnesses) 
14257} 
14358
144- pub ( crate )  fn  lint_nonexhaustive_missing_variants < ' a ,   ' p ,  ' tcx > ( 
145-     cx :   MatchCtxt < ' a ,   ' p ,  ' tcx > , 
146-     arms :  & [ MatchArm < ' p ,  ' tcx > ] , 
147-     pat_column :  & PatternColumn < ' p ,  ' tcx > , 
59+ pub ( crate )  fn  lint_nonexhaustive_missing_variants < ' p ,  ' tcx > ( 
60+     rcx :   & RustcMatchCheckCtxt < ' p ,  ' tcx > , 
61+     arms :  & [ MatchArm < ' p ,  RustcMatchCheckCtxt < ' p ,   ' tcx > > ] , 
62+     pat_column :  & PatternColumn < ' p ,  RustcMatchCheckCtxt < ' p ,   ' tcx > > , 
14863    scrut_ty :  RevealedTy < ' tcx > , 
14964)  -> Result < ( ) ,  ErrorGuaranteed >  { 
150-     let  rcx:  & RustcMatchCheckCtxt < ' _ ,  ' _ >  = cx. tycx ; 
15165    if  !matches ! ( 
15266        rcx. tcx. lint_level_at_node( NON_EXHAUSTIVE_OMITTED_PATTERNS ,  rcx. match_lint_level) . 0 , 
15367        rustc_session:: lint:: Level :: Allow 
15468    )  { 
155-         let  witnesses = collect_nonexhaustive_missing_variants ( cx ,  pat_column) ?; 
69+         let  witnesses = collect_nonexhaustive_missing_variants ( rcx ,  pat_column) ?; 
15670        if  !witnesses. is_empty ( )  { 
15771            // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` 
15872            // is not exhaustive enough. 
0 commit comments