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