@@ -276,7 +276,7 @@ use self::Usefulness::*;
276
276
use self :: WitnessPreference :: * ;
277
277
278
278
use rustc_data_structures:: captures:: Captures ;
279
- use rustc_data_structures:: fx:: FxHashSet ;
279
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
280
280
use rustc_index:: vec:: Idx ;
281
281
282
282
use super :: { compare_const_vals, PatternFoldable , PatternFolder } ;
@@ -504,13 +504,27 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
504
504
}
505
505
}
506
506
507
+ /// Depending on the match patterns, the specialization process might be able to use a fast path.
508
+ /// Tracks whether we can use the fast path and the lookup table needed in those cases.
509
+ #[ derive( Clone , Debug ) ]
510
+ enum SpecializationCache {
511
+ /// Patterns consist of only enum variants.
512
+ Variants { lookup : FxHashMap < DefId , SmallVec < [ usize ; 1 ] > > , wilds : SmallVec < [ usize ; 1 ] > } ,
513
+ /// Does not belong to the cases above, use the slow path.
514
+ Incompatible ,
515
+ }
516
+
507
517
/// A 2D matrix.
508
518
#[ derive( Clone ) ]
509
- crate struct Matrix < ' p , ' tcx > ( Vec < PatStack < ' p , ' tcx > > ) ;
519
+ crate struct Matrix < ' p , ' tcx > {
520
+ patterns : Vec < PatStack < ' p , ' tcx > > ,
521
+ cache : SpecializationCache ,
522
+ }
510
523
511
524
impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
512
525
crate fn empty ( ) -> Self {
513
- Matrix ( vec ! [ ] )
526
+ // Use SpecializationCache::Incompatible as a placeholder; the initialization is in push().
527
+ Matrix { patterns : vec ! [ ] , cache : SpecializationCache :: Incompatible }
514
528
}
515
529
516
530
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
@@ -522,18 +536,65 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
522
536
self . push ( row)
523
537
}
524
538
} else {
525
- self . 0 . push ( row) ;
539
+ if self . patterns . is_empty ( ) {
540
+ self . cache = if row. is_empty ( ) {
541
+ SpecializationCache :: Incompatible
542
+ } else {
543
+ match * row. head ( ) . kind {
544
+ PatKind :: Variant { .. } => SpecializationCache :: Variants {
545
+ lookup : FxHashMap :: default ( ) ,
546
+ wilds : SmallVec :: new ( ) ,
547
+ } ,
548
+ // Note: If the first pattern is a wildcard, then all patterns after that is not
549
+ // useful. The check is simple enough so we treat it as the same as unsupported
550
+ // patterns.
551
+ _ => SpecializationCache :: Incompatible ,
552
+ }
553
+ } ;
554
+ }
555
+ let idx_to_insert = self . patterns . len ( ) ;
556
+ match & mut self . cache {
557
+ SpecializationCache :: Variants { ref mut lookup, ref mut wilds } => {
558
+ let head = row. head ( ) ;
559
+ match * head. kind {
560
+ _ if head. is_wildcard ( ) => {
561
+ for ( _, v) in lookup. iter_mut ( ) {
562
+ v. push ( idx_to_insert) ;
563
+ }
564
+ wilds. push ( idx_to_insert) ;
565
+ }
566
+ PatKind :: Variant { adt_def, variant_index, .. } => {
567
+ lookup
568
+ . entry ( adt_def. variants [ variant_index] . def_id )
569
+ . or_insert_with ( || wilds. clone ( ) )
570
+ . push ( idx_to_insert) ;
571
+ }
572
+ _ => {
573
+ self . cache = SpecializationCache :: Incompatible ;
574
+ }
575
+ }
576
+ }
577
+ SpecializationCache :: Incompatible => { }
578
+ }
579
+ self . patterns . push ( row) ;
526
580
}
527
581
}
528
582
529
583
/// Iterate over the first component of each row
530
584
fn heads < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a Pat < ' tcx > > + Captures < ' p > {
531
- self . 0 . iter ( ) . map ( |r| r. head ( ) )
585
+ self . patterns . iter ( ) . map ( |r| r. head ( ) )
532
586
}
533
587
534
588
/// This computes `D(self)`. See top of the file for explanations.
535
589
fn specialize_wildcard ( & self ) -> Self {
536
- self . 0 . iter ( ) . filter_map ( |r| r. specialize_wildcard ( ) ) . collect ( )
590
+ match & self . cache {
591
+ SpecializationCache :: Variants { wilds, .. } => {
592
+ wilds. iter ( ) . filter_map ( |& i| self . patterns [ i] . specialize_wildcard ( ) ) . collect ( )
593
+ }
594
+ SpecializationCache :: Incompatible => {
595
+ self . patterns . iter ( ) . filter_map ( |r| r. specialize_wildcard ( ) ) . collect ( )
596
+ }
597
+ }
537
598
}
538
599
539
600
/// This computes `S(constructor, self)`. See top of the file for explanations.
@@ -543,10 +604,31 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
543
604
constructor : & Constructor < ' tcx > ,
544
605
ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
545
606
) -> Matrix < ' p , ' tcx > {
546
- self . 0
547
- . iter ( )
548
- . filter_map ( |r| r. specialize_constructor ( cx, constructor, ctor_wild_subpatterns) )
549
- . collect ( )
607
+ match & self . cache {
608
+ SpecializationCache :: Variants { lookup, wilds } => {
609
+ if let Constructor :: Variant ( id) = constructor {
610
+ lookup
611
+ . get ( id)
612
+ . unwrap_or ( & wilds)
613
+ . iter ( )
614
+ . filter_map ( |& i| {
615
+ self . patterns [ i] . specialize_constructor (
616
+ cx,
617
+ constructor,
618
+ ctor_wild_subpatterns,
619
+ )
620
+ } )
621
+ . collect ( )
622
+ } else {
623
+ unreachable ! ( )
624
+ }
625
+ }
626
+ SpecializationCache :: Incompatible => self
627
+ . patterns
628
+ . iter ( )
629
+ . filter_map ( |r| r. specialize_constructor ( cx, constructor, ctor_wild_subpatterns) )
630
+ . collect ( ) ,
631
+ }
550
632
}
551
633
}
552
634
@@ -568,7 +650,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
568
650
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
569
651
write ! ( f, "\n " ) ?;
570
652
571
- let & Matrix ( ref m ) = self ;
653
+ let Matrix { patterns : m , .. } = self ;
572
654
let pretty_printed_matrix: Vec < Vec < String > > =
573
655
m. iter ( ) . map ( |row| row. iter ( ) . map ( |pat| format ! ( "{:?}" , pat) ) . collect ( ) ) . collect ( ) ;
574
656
@@ -1824,7 +1906,7 @@ crate fn is_useful<'p, 'tcx>(
1824
1906
is_under_guard : bool ,
1825
1907
is_top_level : bool ,
1826
1908
) -> Usefulness < ' tcx > {
1827
- let & Matrix ( ref rows) = matrix;
1909
+ let Matrix { patterns : rows, .. } = matrix;
1828
1910
debug ! ( "is_useful({:#?}, {:#?})" , matrix, v) ;
1829
1911
1830
1912
// The base case. We are pattern-matching on () and the return value is
@@ -2266,7 +2348,7 @@ fn split_grouped_constructors<'p, 'tcx>(
2266
2348
// `borders` is the set of borders between equivalence classes: each equivalence
2267
2349
// class lies between 2 borders.
2268
2350
let row_borders = matrix
2269
- . 0
2351
+ . patterns
2270
2352
. iter ( )
2271
2353
. flat_map ( |row| {
2272
2354
IntRange :: from_pat ( tcx, param_env, row. head ( ) ) . map ( |r| ( r, row. len ( ) ) )
0 commit comments