@@ -293,7 +293,7 @@ use self::Usefulness::*;
293
293
use self :: WitnessPreference :: * ;
294
294
295
295
use rustc_data_structures:: captures:: Captures ;
296
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
296
+ use rustc_data_structures:: fx:: FxHashSet ;
297
297
use rustc_data_structures:: sync:: OnceCell ;
298
298
use rustc_index:: vec:: Idx ;
299
299
@@ -401,48 +401,17 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
401
401
}
402
402
}
403
403
404
- /// This computes `S(constructor, self)`. See top of the file for explanations.
405
- ///
406
- /// This is the main specialization step. It expands the pattern
407
- /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
408
- /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
409
- /// Returns `None` if the pattern does not have the given constructor.
404
+ /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
410
405
///
411
- /// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
412
- /// different patterns.
413
406
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
414
407
/// fields filled with wild patterns.
415
408
///
416
409
/// This is roughly the inverse of `Constructor::apply`.
417
- fn specialize_constructor (
418
- & self ,
419
- pcx : PatCtxt < ' _ , ' p , ' tcx > ,
420
- ctor : & Constructor < ' tcx > ,
421
- ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
422
- is_my_head_ctor : bool ,
423
- ) -> Option < PatStack < ' p , ' tcx > > {
424
- // We return `None` if `ctor` is not covered by `self.head()`. If `ctor` is known to be
425
- // derived from `self.head()`, then we don't need to check; otherwise, we check for
426
- // constructor inclusion.
427
- // Note that this shortcut is also necessary for correctness: a pattern should always be
428
- // specializable with its own constructor, even in cases where we refuse to inspect values like
429
- // opaque constants.
430
- if !is_my_head_ctor && !ctor. is_covered_by ( pcx, self . head_ctor ( pcx. cx ) ) {
431
- return None ;
432
- }
433
- let new_fields = ctor_wild_subpatterns. replace_with_pattern_arguments ( self . head ( ) ) ;
434
-
435
- debug ! (
436
- "specialize_constructor({:#?}, {:#?}, {:#?}) = {:#?}" ,
437
- self . head( ) ,
438
- ctor,
439
- ctor_wild_subpatterns,
440
- new_fields
441
- ) ;
442
-
410
+ fn pop_head_constructor ( & self , ctor_wild_subpatterns : & Fields < ' p , ' tcx > ) -> PatStack < ' p , ' tcx > {
443
411
// We pop the head pattern and push the new fields extracted from the arguments of
444
412
// `self.head()`.
445
- Some ( new_fields. push_on_patstack ( & self . pats [ 1 ..] ) )
413
+ let new_fields = ctor_wild_subpatterns. replace_with_pattern_arguments ( self . head ( ) ) ;
414
+ new_fields. push_on_patstack ( & self . pats [ 1 ..] )
446
415
}
447
416
}
448
417
@@ -467,36 +436,15 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
467
436
}
468
437
}
469
438
470
- /// Depending on the match patterns, the specialization process might be able to use a fast path.
471
- /// Tracks whether we can use the fast path and the lookup table needed in those cases.
472
- #[ derive( Clone , Debug , PartialEq ) ]
473
- enum SpecializationCache {
474
- /// Patterns consist of only enum variants.
475
- /// Variant patterns does not intersect with each other (in contrast to range patterns),
476
- /// so it is possible to precompute the result of `Matrix::specialize_constructor` at a
477
- /// lower computational complexity.
478
- /// `lookup` is responsible for holding the precomputed result of
479
- /// specialization, while `wilds` is used for two purposes: the first one is
480
- /// the precomputed result of specialization with a wildcard, and the second is to be used as a
481
- /// fallback for `Matrix::specialize_constructor` when it tries to apply a constructor that
482
- /// has not been seen in the `Matrix`. See `update_cache` for further explanations.
483
- Variants { lookup : FxHashMap < DefId , SmallVec < [ usize ; 1 ] > > , wilds : SmallVec < [ usize ; 1 ] > } ,
484
- /// Does not belong to the cases above, use the slow path.
485
- Incompatible ,
486
- }
487
-
488
439
/// A 2D matrix.
489
440
#[ derive( Clone , PartialEq ) ]
490
441
crate struct Matrix < ' p , ' tcx > {
491
442
patterns : Vec < PatStack < ' p , ' tcx > > ,
492
- cache : SpecializationCache ,
493
443
}
494
444
495
445
impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
496
446
crate fn empty ( ) -> Self {
497
- // Use `SpecializationCache::Incompatible` as a placeholder; we will initialize it on the
498
- // first call to `push`. See the first half of `update_cache`.
499
- Matrix { patterns : vec ! [ ] , cache : SpecializationCache :: Incompatible }
447
+ Matrix { patterns : vec ! [ ] }
500
448
}
501
449
502
450
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
@@ -509,70 +457,6 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
509
457
}
510
458
} else {
511
459
self . patterns . push ( row) ;
512
- self . update_cache ( self . patterns . len ( ) - 1 ) ;
513
- }
514
- }
515
-
516
- fn update_cache ( & mut self , idx : usize ) {
517
- let row = & self . patterns [ idx] ;
518
- // We don't know which kind of cache could be used until we see the first row; therefore an
519
- // empty `Matrix` is initialized with `SpecializationCache::Empty`, then the cache is
520
- // assigned the appropriate variant below on the first call to `push`.
521
- if self . patterns . is_empty ( ) {
522
- self . cache = if row. is_empty ( ) {
523
- SpecializationCache :: Incompatible
524
- } else {
525
- match * row. head ( ) . kind {
526
- PatKind :: Variant { .. } => SpecializationCache :: Variants {
527
- lookup : FxHashMap :: default ( ) ,
528
- wilds : SmallVec :: new ( ) ,
529
- } ,
530
- // Note: If the first pattern is a wildcard, then all patterns after that is not
531
- // useful. The check is simple enough so we treat it as the same as unsupported
532
- // patterns.
533
- _ => SpecializationCache :: Incompatible ,
534
- }
535
- } ;
536
- }
537
- // Update the cache.
538
- match & mut self . cache {
539
- SpecializationCache :: Variants { ref mut lookup, ref mut wilds } => {
540
- let head = row. head ( ) ;
541
- match * head. kind {
542
- _ if head. is_wildcard ( ) => {
543
- // Per rule 1.3 in the top-level comments, a wildcard pattern is included in
544
- // the result of `specialize_constructor` for *any* `Constructor`.
545
- // We push the wildcard pattern to the precomputed result for constructors
546
- // that we have seen before; results for constructors we have not yet seen
547
- // defaults to `wilds`, which is updated right below.
548
- for ( _, v) in lookup. iter_mut ( ) {
549
- v. push ( idx) ;
550
- }
551
- // Per rule 2.1 and 2.2 in the top-level comments, only wildcard patterns
552
- // are included in the result of specialization with a wildcard.
553
- // What we do here is to track the wildcards we have seen; so in addition to
554
- // acting as the precomputed result of specialization with a wildcard, `wilds` also
555
- // serves as the default value of `specialize_constructor` for constructors
556
- // that are not in `lookup`.
557
- wilds. push ( idx) ;
558
- }
559
- PatKind :: Variant { adt_def, variant_index, .. } => {
560
- // Handle the cases of rule 1.1 and 1.2 in the top-level comments.
561
- // A variant pattern can only be included in the results of
562
- // `specialize_constructor` for a particular constructor, therefore we are
563
- // using a HashMap to track that.
564
- lookup
565
- . entry ( adt_def. variants [ variant_index] . def_id )
566
- // Default to `wilds` for absent keys. See above for an explanation.
567
- . or_insert_with ( || wilds. clone ( ) )
568
- . push ( idx) ;
569
- }
570
- _ => {
571
- self . cache = SpecializationCache :: Incompatible ;
572
- }
573
- }
574
- }
575
- SpecializationCache :: Incompatible => { }
576
460
}
577
461
}
578
462
@@ -593,59 +477,14 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
593
477
fn specialize_constructor (
594
478
& self ,
595
479
pcx : PatCtxt < ' _ , ' p , ' tcx > ,
596
- constructor : & Constructor < ' tcx > ,
480
+ ctor : & Constructor < ' tcx > ,
597
481
ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
598
482
) -> Matrix < ' p , ' tcx > {
599
- match & self . cache {
600
- SpecializationCache :: Variants { lookup, wilds } => {
601
- let cached = if let Constructor :: Variant ( id) = constructor {
602
- lookup
603
- . get ( id)
604
- // Default to `wilds` for absent keys. See `update_cache` for an explanation.
605
- . unwrap_or ( & wilds)
606
- } else if let Wildcard = constructor {
607
- & wilds
608
- } else {
609
- bug ! (
610
- "unexpected constructor encountered while dealing with matrix cache: {:?}" ,
611
- constructor
612
- ) ;
613
- } ;
614
- let result: Self = cached
615
- . iter ( )
616
- . filter_map ( |& i| {
617
- self . patterns [ i] . specialize_constructor (
618
- pcx,
619
- constructor,
620
- ctor_wild_subpatterns,
621
- false ,
622
- )
623
- } )
624
- . collect ( ) ;
625
- // When debug assertions are enabled, check the results against the "slow path"
626
- // result.
627
- debug_assert_eq ! (
628
- result,
629
- Matrix {
630
- patterns: self . patterns. clone( ) ,
631
- cache: SpecializationCache :: Incompatible
632
- }
633
- . specialize_constructor(
634
- pcx,
635
- constructor,
636
- ctor_wild_subpatterns
637
- )
638
- ) ;
639
- result
640
- }
641
- SpecializationCache :: Incompatible => self
642
- . patterns
643
- . iter ( )
644
- . filter_map ( |r| {
645
- r. specialize_constructor ( pcx, constructor, ctor_wild_subpatterns, false )
646
- } )
647
- . collect ( ) ,
648
- }
483
+ self . patterns
484
+ . iter ( )
485
+ . filter ( |r| ctor. is_covered_by ( pcx, r. head_ctor ( pcx. cx ) ) )
486
+ . map ( |r| r. pop_head_constructor ( ctor_wild_subpatterns) )
487
+ . collect ( )
649
488
}
650
489
}
651
490
@@ -2442,8 +2281,7 @@ crate fn is_useful<'p, 'tcx>(
2442
2281
// We cache the result of `Fields::wildcards` because it is used a lot.
2443
2282
let ctor_wild_subpatterns = Fields :: wildcards ( pcx, & ctor) ;
2444
2283
let matrix = pcx. matrix . specialize_constructor ( pcx, & ctor, & ctor_wild_subpatterns) ;
2445
- // Unwrap is ok: v can always be specialized with its own constructor.
2446
- let v = v. specialize_constructor ( pcx, & ctor, & ctor_wild_subpatterns, true ) . unwrap ( ) ;
2284
+ let v = v. pop_head_constructor ( & ctor_wild_subpatterns) ;
2447
2285
let usefulness =
2448
2286
is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
2449
2287
usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns, is_top_level)
0 commit comments