@@ -667,16 +667,15 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
667667#[ derive( Clone ) ]
668668struct Matrix < ' p , ' tcx > {
669669 rows : Vec < PatStack < ' p , ' tcx > > ,
670+ /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
671+ /// each column. This must obey the same invariants as the real rows.
672+ wildcard_row : PatStack < ' p , ' tcx > ,
670673}
671674
672675impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
673- /// Make an empty matrix. Internal method, prefer [`Matrix::new`].
674- fn empty ( ) -> Self {
675- Matrix { rows : vec ! [ ] }
676- }
677676 /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
678677 /// expands it. Internal method, prefer [`Matrix::new`].
679- fn push ( & mut self , row : PatStack < ' p , ' tcx > ) {
678+ fn expand_and_push ( & mut self , row : PatStack < ' p , ' tcx > ) {
680679 if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
681680 // Expand nested or-patterns.
682681 for new_row in row. expand_or_pat ( ) {
@@ -688,18 +687,48 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
688687 }
689688
690689 /// Build a new matrix from an iterator of `MatchArm`s.
691- fn new < ' a > ( iter : impl Iterator < Item = & ' a MatchArm < ' p , ' tcx > > ) -> Self
690+ fn new < ' a > (
691+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
692+ iter : impl Iterator < Item = & ' a MatchArm < ' p , ' tcx > > ,
693+ scrut_ty : Ty < ' tcx > ,
694+ ) -> Self
692695 where
693696 ' p : ' a ,
694697 {
695- let mut matrix = Matrix :: empty ( ) ;
698+ let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
699+ let wildcard_row = PatStack :: from_pattern ( wild_pattern, usize:: MAX , false ) ;
700+ let mut matrix = Matrix { rows : vec ! [ ] , wildcard_row } ;
696701 for ( row_id, arm) in iter. enumerate ( ) {
697702 let v = PatStack :: from_pattern ( arm. pat , row_id, arm. has_guard ) ;
698- matrix. push ( v) ;
703+ matrix. expand_and_push ( v) ;
699704 }
700705 matrix
701706 }
702707
708+ fn head_ty ( & self ) -> Option < Ty < ' tcx > > {
709+ if self . column_count ( ) == 0 {
710+ return None ;
711+ }
712+
713+ let mut ty = self . wildcard_row . head ( ) . ty ( ) ;
714+ // If the type is opaque and it is revealed anywhere in the column, we take the revealed
715+ // version. Otherwise we could encounter constructors for the revealed type and crash.
716+ let is_opaque = |ty : Ty < ' tcx > | matches ! ( ty. kind( ) , ty:: Alias ( ty:: Opaque , ..) ) ;
717+ if is_opaque ( ty) {
718+ for pat in self . heads ( ) {
719+ let pat_ty = pat. ty ( ) ;
720+ if !is_opaque ( pat_ty) {
721+ ty = pat_ty;
722+ break ;
723+ }
724+ }
725+ }
726+ Some ( ty)
727+ }
728+ fn column_count ( & self ) -> usize {
729+ self . wildcard_row . len ( )
730+ }
731+
703732 fn rows < ' a > (
704733 & ' a self ,
705734 ) -> impl Iterator < Item = & ' a PatStack < ' p , ' tcx > > + Clone + DoubleEndedIterator + ExactSizeIterator
@@ -726,11 +755,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
726755 pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
727756 ctor : & Constructor < ' tcx > ,
728757 ) -> Matrix < ' p , ' tcx > {
729- let mut matrix = Matrix :: empty ( ) ;
758+ let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor, usize:: MAX ) ;
759+ let mut matrix = Matrix { rows : vec ! [ ] , wildcard_row } ;
730760 for ( i, row) in self . rows ( ) . enumerate ( ) {
731761 if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
732762 let new_row = row. pop_head_constructor ( pcx, ctor, i) ;
733- matrix. push ( new_row) ;
763+ matrix. expand_and_push ( new_row) ;
734764 }
735765 }
736766 matrix
@@ -965,21 +995,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
965995/// - unspecialization, where we lift the results from the previous step into results for this step
966996/// (using `apply_constructor` and by updating `row.reachable` for each parent row).
967997/// This is all explained at the top of the file.
968- ///
969- /// `wildcard_row` is a fictitious matrix row that has only wildcards, with the appropriate types to
970- /// match what's in the columns of `matrix`.
971998#[ instrument( level = "debug" , skip( cx, is_top_level) , ret) ]
972999fn compute_exhaustiveness_and_reachability < ' p , ' tcx > (
9731000 cx : & MatchCheckCtxt < ' p , ' tcx > ,
9741001 matrix : & mut Matrix < ' p , ' tcx > ,
975- wildcard_row : & PatStack < ' p , ' tcx > ,
9761002 is_top_level : bool ,
9771003) -> WitnessMatrix < ' tcx > {
978- debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == wildcard_row . len ( ) ) ) ;
1004+ debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix . column_count ( ) ) ) ;
9791005
980- if wildcard_row . is_empty ( ) {
981- // The base case. We are morally pattern-matching on (). A row is reachable iff it has no
982- // (unguarded) rows above it.
1006+ let Some ( ty ) = matrix . head_ty ( ) else {
1007+ // The base case: there are no columns in the matrix . We are morally pattern-matching on ().
1008+ // A row is reachable iff it has no (unguarded) rows above it.
9831009 for row in matrix. rows_mut ( ) {
9841010 // All rows are reachable until we find one without a guard.
9851011 row. reachable = true ;
@@ -991,21 +1017,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
9911017 }
9921018 // No (unguarded) rows, so the match is not exhaustive. We return a new witness.
9931019 return WitnessMatrix :: unit_witness ( ) ;
994- }
995-
996- let mut ty = wildcard_row. head ( ) . ty ( ) ;
997- // If the type is opaque and it is revealed anywhere in the column, we take the revealed
998- // version. Otherwise we could encounter constructors for the revealed type and crash.
999- let is_opaque = |ty : Ty < ' tcx > | matches ! ( ty. kind( ) , ty:: Alias ( ty:: Opaque , ..) ) ;
1000- if is_opaque ( ty) {
1001- for pat in matrix. heads ( ) {
1002- let pat_ty = pat. ty ( ) ;
1003- if !is_opaque ( pat_ty) {
1004- ty = pat_ty;
1005- break ;
1006- }
1007- }
1008- }
1020+ } ;
10091021
10101022 debug ! ( "ty: {ty:?}" ) ;
10111023 let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level } ;
@@ -1033,9 +1045,8 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
10331045 debug ! ( "specialize({:?})" , ctor) ;
10341046 // Dig into rows that match `ctor`.
10351047 let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
1036- let wildcard_row = wildcard_row. pop_head_constructor ( pcx, & ctor, usize:: MAX ) ;
10371048 let mut witnesses = ensure_sufficient_stack ( || {
1038- compute_exhaustiveness_and_reachability ( cx, & mut spec_matrix, & wildcard_row , false )
1049+ compute_exhaustiveness_and_reachability ( cx, & mut spec_matrix, false )
10391050 } ) ;
10401051 // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
10411052 witnesses. apply_constructor ( pcx, & split_set. missing , & ctor) ;
@@ -1312,11 +1323,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
13121323 scrut_ty : Ty < ' tcx > ,
13131324 scrut_span : Span ,
13141325) -> UsefulnessReport < ' p , ' tcx > {
1315- let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
1316- let wildcard_row = PatStack :: from_pattern ( wild_pattern, usize:: MAX , false ) ;
1317- let mut matrix = Matrix :: new ( arms. iter ( ) ) ;
1326+ let mut matrix = Matrix :: new ( cx, arms. iter ( ) , scrut_ty) ;
13181327 let non_exhaustiveness_witnesses =
1319- compute_exhaustiveness_and_reachability ( cx, & mut matrix, & wildcard_row , true ) ;
1328+ compute_exhaustiveness_and_reachability ( cx, & mut matrix, true ) ;
13201329
13211330 let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
13221331 let arm_usefulness: Vec < _ > = arms
0 commit comments