@@ -380,16 +380,17 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
380
380
/// works well.
381
381
#[ derive( Clone ) ]
382
382
pub ( crate ) struct PatStack < ' p , ' tcx > {
383
- pub ( crate ) pats : SmallVec < [ & ' p DeconstructedPat < ' p , ' tcx > ; 2 ] > ,
383
+ pats : SmallVec < [ & ' p DeconstructedPat < ' p , ' tcx > ; 2 ] > ,
384
+ is_under_guard : bool ,
384
385
}
385
386
386
387
impl < ' p , ' tcx > PatStack < ' p , ' tcx > {
387
- fn from_pattern ( pat : & ' p DeconstructedPat < ' p , ' tcx > ) -> Self {
388
- Self :: from_vec ( smallvec ! [ pat] )
388
+ fn from_pattern ( pat : & ' p DeconstructedPat < ' p , ' tcx > , is_under_guard : bool ) -> Self {
389
+ PatStack { pats : smallvec ! [ pat] , is_under_guard }
389
390
}
390
391
391
- fn from_vec ( vec : SmallVec < [ & ' p DeconstructedPat < ' p , ' tcx > ; 2 ] > ) -> Self {
392
- PatStack { pats : vec }
392
+ fn from_vec ( vec : SmallVec < [ & ' p DeconstructedPat < ' p , ' tcx > ; 2 ] > , is_under_guard : bool ) -> Self {
393
+ PatStack { pats : vec, is_under_guard }
393
394
}
394
395
395
396
fn is_empty ( & self ) -> bool {
@@ -412,7 +413,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
412
413
// or-pattern. Panics if `self` is empty.
413
414
fn expand_or_pat < ' a > ( & ' a self ) -> impl Iterator < Item = PatStack < ' p , ' tcx > > + Captures < ' a > {
414
415
self . head ( ) . iter_fields ( ) . map ( move |pat| {
415
- let mut new_patstack = PatStack :: from_pattern ( pat) ;
416
+ let mut new_patstack = PatStack :: from_pattern ( pat, self . is_under_guard ) ;
416
417
new_patstack. pats . extend_from_slice ( & self . pats [ 1 ..] ) ;
417
418
new_patstack
418
419
} )
@@ -422,7 +423,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
422
423
fn expand_and_extend < ' a > ( & ' a self , matrix : & mut Matrix < ' p , ' tcx > ) {
423
424
if !self . is_empty ( ) && self . head ( ) . is_or_pat ( ) {
424
425
for pat in self . head ( ) . iter_fields ( ) {
425
- let mut new_patstack = PatStack :: from_pattern ( pat) ;
426
+ let mut new_patstack = PatStack :: from_pattern ( pat, self . is_under_guard ) ;
426
427
new_patstack. pats . extend_from_slice ( & self . pats [ 1 ..] ) ;
427
428
if !new_patstack. is_empty ( ) && new_patstack. head ( ) . is_or_pat ( ) {
428
429
new_patstack. expand_and_extend ( matrix) ;
@@ -448,7 +449,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
448
449
// `self.head()`.
449
450
let mut new_fields: SmallVec < [ _ ; 2 ] > = self . head ( ) . specialize ( pcx, ctor) ;
450
451
new_fields. extend_from_slice ( & self . pats [ 1 ..] ) ;
451
- PatStack :: from_vec ( new_fields)
452
+ PatStack :: from_vec ( new_fields, self . is_under_guard )
452
453
}
453
454
}
454
455
@@ -466,12 +467,12 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
466
467
/// A 2D matrix.
467
468
#[ derive( Clone ) ]
468
469
pub ( super ) struct Matrix < ' p , ' tcx > {
469
- pub patterns : Vec < PatStack < ' p , ' tcx > > ,
470
+ pub rows : Vec < PatStack < ' p , ' tcx > > ,
470
471
}
471
472
472
473
impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
473
474
fn empty ( ) -> Self {
474
- Matrix { patterns : vec ! [ ] }
475
+ Matrix { rows : vec ! [ ] }
475
476
}
476
477
477
478
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
@@ -480,15 +481,22 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
480
481
if !row. is_empty ( ) && row. head ( ) . is_or_pat ( ) {
481
482
row. expand_and_extend ( self ) ;
482
483
} else {
483
- self . patterns . push ( row) ;
484
+ self . rows . push ( row) ;
484
485
}
485
486
}
486
487
488
+ fn rows < ' a > (
489
+ & ' a self ,
490
+ ) -> impl Iterator < Item = & ' a PatStack < ' p , ' tcx > > + Clone + DoubleEndedIterator + ExactSizeIterator
491
+ {
492
+ self . rows . iter ( )
493
+ }
494
+
487
495
/// Iterate over the first component of each row
488
496
fn heads < ' a > (
489
497
& ' a self ,
490
498
) -> impl Iterator < Item = & ' p DeconstructedPat < ' p , ' tcx > > + Clone + Captures < ' a > {
491
- self . patterns . iter ( ) . map ( |r| r. head ( ) )
499
+ self . rows ( ) . map ( |r| r. head ( ) )
492
500
}
493
501
494
502
/// This computes `S(constructor, self)`. See top of the file for explanations.
@@ -498,7 +506,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
498
506
ctor : & Constructor < ' tcx > ,
499
507
) -> Matrix < ' p , ' tcx > {
500
508
let mut matrix = Matrix :: empty ( ) ;
501
- for row in & self . patterns {
509
+ for row in & self . rows {
502
510
if ctor. is_covered_by ( pcx, row. head ( ) . ctor ( ) ) {
503
511
let new_row = row. pop_head_constructor ( pcx, ctor) ;
504
512
matrix. push ( new_row) ;
@@ -521,12 +529,12 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
521
529
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
522
530
write ! ( f, "\n " ) ?;
523
531
524
- let Matrix { patterns : m , .. } = self ;
532
+ let Matrix { rows , .. } = self ;
525
533
let pretty_printed_matrix: Vec < Vec < String > > =
526
- m . iter ( ) . map ( |row| row. iter ( ) . map ( |pat| format ! ( "{pat:?}" ) ) . collect ( ) ) . collect ( ) ;
534
+ rows . iter ( ) . map ( |row| row. iter ( ) . map ( |pat| format ! ( "{pat:?}" ) ) . collect ( ) ) . collect ( ) ;
527
535
528
- let column_count = m . iter ( ) . map ( |row| row. len ( ) ) . next ( ) . unwrap_or ( 0 ) ;
529
- assert ! ( m . iter( ) . all( |row| row. len( ) == column_count) ) ;
536
+ let column_count = rows . iter ( ) . map ( |row| row. len ( ) ) . next ( ) . unwrap_or ( 0 ) ;
537
+ assert ! ( rows . iter( ) . all( |row| row. len( ) == column_count) ) ;
530
538
let column_widths: Vec < usize > = ( 0 ..column_count)
531
539
. map ( |col| pretty_printed_matrix. iter ( ) . map ( |row| row[ col] . len ( ) ) . max ( ) . unwrap_or ( 0 ) )
532
540
. collect ( ) ;
@@ -808,19 +816,16 @@ fn is_useful<'p, 'tcx>(
808
816
v : & PatStack < ' p , ' tcx > ,
809
817
witness_preference : ArmType ,
810
818
lint_root : HirId ,
811
- is_under_guard : bool ,
812
819
is_top_level : bool ,
813
820
) -> Usefulness < ' tcx > {
814
821
debug ! ( ?matrix, ?v) ;
815
- let Matrix { patterns : rows, .. } = matrix;
816
-
817
822
// The base case. We are pattern-matching on () and the return value is
818
823
// based on whether our matrix has a row or not.
819
824
// NOTE: This could potentially be optimized by checking rows.is_empty()
820
825
// first and then, if v is non-empty, the return value is based on whether
821
826
// the type of the tuple we're checking is inhabited or not.
822
827
if v. is_empty ( ) {
823
- let ret = if rows. is_empty ( ) {
828
+ let ret = if matrix . rows ( ) . all ( |r| r . is_under_guard ) {
824
829
Usefulness :: new_useful ( witness_preference)
825
830
} else {
826
831
Usefulness :: new_not_useful ( witness_preference)
@@ -829,7 +834,7 @@ fn is_useful<'p, 'tcx>(
829
834
return ret;
830
835
}
831
836
832
- debug_assert ! ( rows . iter ( ) . all( |r| r. len( ) == v. len( ) ) ) ;
837
+ debug_assert ! ( matrix . rows ( ) . all( |r| r. len( ) == v. len( ) ) ) ;
833
838
834
839
// If the first pattern is an or-pattern, expand it.
835
840
let mut ret = Usefulness :: new_not_useful ( witness_preference) ;
@@ -840,24 +845,21 @@ fn is_useful<'p, 'tcx>(
840
845
for v in v. expand_or_pat ( ) {
841
846
debug ! ( ?v) ;
842
847
let usefulness = ensure_sufficient_stack ( || {
843
- is_useful ( cx, & matrix, & v, witness_preference, lint_root, is_under_guard , false )
848
+ is_useful ( cx, & matrix, & v, witness_preference, lint_root, false )
844
849
} ) ;
845
850
debug ! ( ?usefulness) ;
846
851
ret. extend ( usefulness) ;
847
- // If pattern has a guard don't add it to the matrix.
848
- if !is_under_guard {
849
- // We push the already-seen patterns into the matrix in order to detect redundant
850
- // branches like `Some(_) | Some(0)`.
851
- matrix. push ( v) ;
852
- }
852
+ // We push the already-seen patterns into the matrix in order to detect redundant
853
+ // branches like `Some(_) | Some(0)`.
854
+ matrix. push ( v) ;
853
855
}
854
856
} else {
855
857
let mut ty = v. head ( ) . ty ( ) ;
856
858
857
859
// Opaque types can't get destructured/split, but the patterns can
858
860
// actually hint at hidden types, so we use the patterns' types instead.
859
861
if let ty:: Alias ( ty:: Opaque , ..) = ty. kind ( ) {
860
- if let Some ( row) = rows. first ( ) {
862
+ if let Some ( row) = matrix . rows ( ) . next ( ) {
861
863
ty = row. head ( ) . ty ( ) ;
862
864
}
863
865
}
@@ -877,15 +879,7 @@ fn is_useful<'p, 'tcx>(
877
879
let spec_matrix = start_matrix. specialize_constructor ( pcx, & ctor) ;
878
880
let v = v. pop_head_constructor ( pcx, & ctor) ;
879
881
let usefulness = ensure_sufficient_stack ( || {
880
- is_useful (
881
- cx,
882
- & spec_matrix,
883
- & v,
884
- witness_preference,
885
- lint_root,
886
- is_under_guard,
887
- false ,
888
- )
882
+ is_useful ( cx, & spec_matrix, & v, witness_preference, lint_root, false )
889
883
} ) ;
890
884
let usefulness = usefulness. apply_constructor ( pcx, start_matrix, & ctor) ;
891
885
ret. extend ( usefulness) ;
@@ -1118,11 +1112,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1118
1112
. copied ( )
1119
1113
. map ( |arm| {
1120
1114
debug ! ( ?arm) ;
1121
- let v = PatStack :: from_pattern ( arm. pat ) ;
1122
- is_useful ( cx, & matrix, & v, RealArm , arm. hir_id , arm. has_guard , true ) ;
1123
- if !arm. has_guard {
1124
- matrix. push ( v) ;
1125
- }
1115
+ let v = PatStack :: from_pattern ( arm. pat , arm. has_guard ) ;
1116
+ is_useful ( cx, & matrix, & v, RealArm , arm. hir_id , true ) ;
1117
+ matrix. push ( v) ;
1126
1118
let reachability = if arm. pat . is_reachable ( ) {
1127
1119
Reachability :: Reachable ( arm. pat . unreachable_spans ( ) )
1128
1120
} else {
@@ -1133,8 +1125,8 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1133
1125
. collect ( ) ;
1134
1126
1135
1127
let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
1136
- let v = PatStack :: from_pattern ( wild_pattern) ;
1137
- let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
1128
+ let v = PatStack :: from_pattern ( wild_pattern, false ) ;
1129
+ let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, true ) ;
1138
1130
let non_exhaustiveness_witnesses: Vec < _ > = match usefulness {
1139
1131
WithWitnesses ( witness_matrix) => witness_matrix. single_column ( ) ,
1140
1132
NoWitnesses { .. } => bug ! ( ) ,
0 commit comments