@@ -666,16 +666,15 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
666666#[ derive( Clone ) ]
667667struct Matrix < ' p , ' tcx > {
668668 rows : Vec < PatStack < ' p , ' tcx > > ,
669+ /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
670+ /// each column. This must obey the same invariants as the real rows.
671+ wildcard_row : PatStack < ' p , ' tcx > ,
669672}
670673
671674impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
672- /// Make an empty matrix. Internal method, prefer [`Matrix::new`].
673- fn empty ( ) -> Self {
674- Matrix { rows : vec ! [ ] }
675- }
676675 /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
677676 /// expands it. Internal method, prefer [`Matrix::new`].
678- fn push ( & mut self , row : PatStack < ' p , ' tcx > ) {
677+ fn expand_and_push ( & mut self , row : PatStack < ' p , ' tcx > ) {
679678 if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
680679 // Expand nested or-patterns.
681680 for new_row in row. expand_or_pat ( ) {
@@ -687,18 +686,48 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
687686 }
688687
689688 /// Build a new matrix from an iterator of `MatchArm`s.
690- fn new < ' a > ( iter : impl Iterator < Item = & ' a MatchArm < ' p , ' tcx > > ) -> Self
689+ fn new < ' a > (
690+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
691+ iter : impl Iterator < Item = & ' a MatchArm < ' p , ' tcx > > ,
692+ scrut_ty : Ty < ' tcx > ,
693+ ) -> Self
691694 where
692695 ' p : ' a ,
693696 {
694- let mut matrix = Matrix :: empty ( ) ;
697+ let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
698+ let wildcard_row = PatStack :: from_pattern ( wild_pattern, usize:: MAX , false ) ;
699+ let mut matrix = Matrix { rows : vec ! [ ] , wildcard_row } ;
695700 for ( row_id, arm) in iter. enumerate ( ) {
696701 let v = PatStack :: from_pattern ( arm. pat , row_id, arm. has_guard ) ;
697- matrix. push ( v) ;
702+ matrix. expand_and_push ( v) ;
698703 }
699704 matrix
700705 }
701706
707+ fn head_ty ( & self ) -> Option < Ty < ' tcx > > {
708+ if self . column_count ( ) == 0 {
709+ return None ;
710+ }
711+
712+ let mut ty = self . wildcard_row . head ( ) . ty ( ) ;
713+ // If the type is opaque and it is revealed anywhere in the column, we take the revealed
714+ // version. Otherwise we could encounter constructors for the revealed type and crash.
715+ let is_opaque = |ty : Ty < ' tcx > | matches ! ( ty. kind( ) , ty:: Alias ( ty:: Opaque , ..) ) ;
716+ if is_opaque ( ty) {
717+ for pat in self . heads ( ) {
718+ let pat_ty = pat. ty ( ) ;
719+ if !is_opaque ( pat_ty) {
720+ ty = pat_ty;
721+ break ;
722+ }
723+ }
724+ }
725+ Some ( ty)
726+ }
727+ fn column_count ( & self ) -> usize {
728+ self . wildcard_row . len ( )
729+ }
730+
702731 fn rows < ' a > (
703732 & ' a self ,
704733 ) -> impl Iterator < Item = & ' a PatStack < ' p , ' tcx > > + Clone + DoubleEndedIterator + ExactSizeIterator
@@ -725,11 +754,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
725754 pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
726755 ctor : & Constructor < ' tcx > ,
727756 ) -> Matrix < ' p , ' tcx > {
728- let mut matrix = Matrix :: empty ( ) ;
757+ let wildcard_row = self . wildcard_row . pop_head_constructor ( pcx, ctor, usize:: MAX ) ;
758+ let mut matrix = Matrix { rows : vec ! [ ] , wildcard_row } ;
729759 for ( i, row) in self . rows ( ) . enumerate ( ) {
730760 if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
731761 let new_row = row. pop_head_constructor ( pcx, ctor, i) ;
732- matrix. push ( new_row) ;
762+ matrix. expand_and_push ( new_row) ;
733763 }
734764 }
735765 matrix
@@ -964,21 +994,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
964994/// - unspecialization, where we lift the results from the previous step into results for this step
965995/// (using `apply_constructor` and by updating `row.reachable` for each parent row).
966996/// This is all explained at the top of the file.
967- ///
968- /// `wildcard_row` is a fictitious matrix row that has only wildcards, with the appropriate types to
969- /// match what's in the columns of `matrix`.
970997#[ instrument( level = "debug" , skip( cx, is_top_level) , ret) ]
971998fn compute_exhaustiveness_and_reachability < ' p , ' tcx > (
972999 cx : & MatchCheckCtxt < ' p , ' tcx > ,
9731000 matrix : & mut Matrix < ' p , ' tcx > ,
974- wildcard_row : & PatStack < ' p , ' tcx > ,
9751001 is_top_level : bool ,
9761002) -> WitnessMatrix < ' tcx > {
977- debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == wildcard_row . len ( ) ) ) ;
1003+ debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix . column_count ( ) ) ) ;
9781004
979- if wildcard_row . is_empty ( ) {
980- // The base case. We are morally pattern-matching on (). A row is reachable iff it has no
981- // (unguarded) rows above it.
1005+ let Some ( ty ) = matrix . head_ty ( ) else {
1006+ // The base case: there are no columns in the matrix . We are morally pattern-matching on ().
1007+ // A row is reachable iff it has no (unguarded) rows above it.
9821008 for row in matrix. rows_mut ( ) {
9831009 // All rows are reachable until we find one without a guard.
9841010 row. reachable = true ;
@@ -990,21 +1016,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
9901016 }
9911017 // No (unguarded) rows, so the match is not exhaustive. We return a new witness.
9921018 return WitnessMatrix :: unit_witness ( ) ;
993- }
994-
995- let mut ty = wildcard_row. head ( ) . ty ( ) ;
996- // If the type is opaque and it is revealed anywhere in the column, we take the revealed
997- // version. Otherwise we could encounter constructors for the revealed type and crash.
998- let is_opaque = |ty : Ty < ' tcx > | matches ! ( ty. kind( ) , ty:: Alias ( ty:: Opaque , ..) ) ;
999- if is_opaque ( ty) {
1000- for pat in matrix. heads ( ) {
1001- let pat_ty = pat. ty ( ) ;
1002- if !is_opaque ( pat_ty) {
1003- ty = pat_ty;
1004- break ;
1005- }
1006- }
1007- }
1019+ } ;
10081020
10091021 debug ! ( "ty: {ty:?}" ) ;
10101022 let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level } ;
@@ -1032,9 +1044,8 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
10321044 debug ! ( "specialize({:?})" , ctor) ;
10331045 // Dig into rows that match `ctor`.
10341046 let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
1035- let wildcard_row = wildcard_row. pop_head_constructor ( pcx, & ctor, usize:: MAX ) ;
10361047 let mut witnesses = ensure_sufficient_stack ( || {
1037- compute_exhaustiveness_and_reachability ( cx, & mut spec_matrix, & wildcard_row , false )
1048+ compute_exhaustiveness_and_reachability ( cx, & mut spec_matrix, false )
10381049 } ) ;
10391050 // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
10401051 witnesses. apply_constructor ( pcx, & split_set. missing , & ctor) ;
@@ -1311,11 +1322,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
13111322 scrut_ty : Ty < ' tcx > ,
13121323 scrut_span : Span ,
13131324) -> UsefulnessReport < ' p , ' tcx > {
1314- let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
1315- let wildcard_row = PatStack :: from_pattern ( wild_pattern, usize:: MAX , false ) ;
1316- let mut matrix = Matrix :: new ( arms. iter ( ) ) ;
1325+ let mut matrix = Matrix :: new ( cx, arms. iter ( ) , scrut_ty) ;
13171326 let non_exhaustiveness_witnesses =
1318- compute_exhaustiveness_and_reachability ( cx, & mut matrix, & wildcard_row , true ) ;
1327+ compute_exhaustiveness_and_reachability ( cx, & mut matrix, true ) ;
13191328
13201329 let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
13211330 let arm_usefulness: Vec < _ > = arms
0 commit comments