@@ -667,16 +667,15 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
667
667
#[ derive( Clone ) ]
668
668
struct Matrix < ' p , ' tcx > {
669
669
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 > ,
670
673
}
671
674
672
675
impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
673
- /// Make an empty matrix. Internal method, prefer [`Matrix::new`].
674
- fn empty ( ) -> Self {
675
- Matrix { rows : vec ! [ ] }
676
- }
677
676
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
678
677
/// 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 > ) {
680
679
if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
681
680
// Expand nested or-patterns.
682
681
for new_row in row. expand_or_pat ( ) {
@@ -688,18 +687,48 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
688
687
}
689
688
690
689
/// 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
692
695
where
693
696
' p : ' a ,
694
697
{
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 } ;
696
701
for ( row_id, arm) in iter. enumerate ( ) {
697
702
let v = PatStack :: from_pattern ( arm. pat , row_id, arm. has_guard ) ;
698
- matrix. push ( v) ;
703
+ matrix. expand_and_push ( v) ;
699
704
}
700
705
matrix
701
706
}
702
707
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
+
703
732
fn rows < ' a > (
704
733
& ' a self ,
705
734
) -> impl Iterator < Item = & ' a PatStack < ' p , ' tcx > > + Clone + DoubleEndedIterator + ExactSizeIterator
@@ -726,11 +755,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
726
755
pcx : & PatCtxt < ' _ , ' p , ' tcx > ,
727
756
ctor : & Constructor < ' tcx > ,
728
757
) -> 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 } ;
730
760
for ( i, row) in self . rows ( ) . enumerate ( ) {
731
761
if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
732
762
let new_row = row. pop_head_constructor ( pcx, ctor, i) ;
733
- matrix. push ( new_row) ;
763
+ matrix. expand_and_push ( new_row) ;
734
764
}
735
765
}
736
766
matrix
@@ -965,21 +995,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
965
995
/// - unspecialization, where we lift the results from the previous step into results for this step
966
996
/// (using `apply_constructor` and by updating `row.reachable` for each parent row).
967
997
/// 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`.
971
998
#[ instrument( level = "debug" , skip( cx, is_top_level) , ret) ]
972
999
fn compute_exhaustiveness_and_reachability < ' p , ' tcx > (
973
1000
cx : & MatchCheckCtxt < ' p , ' tcx > ,
974
1001
matrix : & mut Matrix < ' p , ' tcx > ,
975
- wildcard_row : & PatStack < ' p , ' tcx > ,
976
1002
is_top_level : bool ,
977
1003
) -> 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 ( ) ) ) ;
979
1005
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.
983
1009
for row in matrix. rows_mut ( ) {
984
1010
// All rows are reachable until we find one without a guard.
985
1011
row. reachable = true ;
@@ -991,21 +1017,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
991
1017
}
992
1018
// No (unguarded) rows, so the match is not exhaustive. We return a new witness.
993
1019
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
+ } ;
1009
1021
1010
1022
debug ! ( "ty: {ty:?}" ) ;
1011
1023
let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level } ;
@@ -1033,9 +1045,8 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
1033
1045
debug ! ( "specialize({:?})" , ctor) ;
1034
1046
// Dig into rows that match `ctor`.
1035
1047
let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
1036
- let wildcard_row = wildcard_row. pop_head_constructor ( pcx, & ctor, usize:: MAX ) ;
1037
1048
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 )
1039
1050
} ) ;
1040
1051
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1041
1052
witnesses. apply_constructor ( pcx, & split_set. missing , & ctor) ;
@@ -1312,11 +1323,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1312
1323
scrut_ty : Ty < ' tcx > ,
1313
1324
scrut_span : Span ,
1314
1325
) -> 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) ;
1318
1327
let non_exhaustiveness_witnesses =
1319
- compute_exhaustiveness_and_reachability ( cx, & mut matrix, & wildcard_row , true ) ;
1328
+ compute_exhaustiveness_and_reachability ( cx, & mut matrix, true ) ;
1320
1329
1321
1330
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1322
1331
let arm_usefulness: Vec < _ > = arms
0 commit comments