@@ -293,7 +293,7 @@ use self::Usefulness::*;
293293use self :: WitnessPreference :: * ;
294294
295295use rustc_data_structures:: captures:: Captures ;
296- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
296+ use rustc_data_structures:: fx:: FxHashSet ;
297297use rustc_data_structures:: sync:: OnceCell ;
298298use rustc_index:: vec:: Idx ;
299299
@@ -401,48 +401,17 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
401401 }
402402 }
403403
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.
410405 ///
411- /// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
412- /// different patterns.
413406 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
414407 /// fields filled with wild patterns.
415408 ///
416409 /// 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 > {
443411 // We pop the head pattern and push the new fields extracted from the arguments of
444412 // `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 ..] )
446415 }
447416}
448417
@@ -467,36 +436,15 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
467436 }
468437}
469438
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-
488439/// A 2D matrix.
489440#[ derive( Clone , PartialEq ) ]
490441crate struct Matrix < ' p , ' tcx > {
491442 patterns : Vec < PatStack < ' p , ' tcx > > ,
492- cache : SpecializationCache ,
493443}
494444
495445impl < ' p , ' tcx > Matrix < ' p , ' tcx > {
496446 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 ! [ ] }
500448 }
501449
502450 /// 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> {
509457 }
510458 } else {
511459 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 => { }
576460 }
577461 }
578462
@@ -593,59 +477,14 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
593477 fn specialize_constructor (
594478 & self ,
595479 pcx : PatCtxt < ' _ , ' p , ' tcx > ,
596- constructor : & Constructor < ' tcx > ,
480+ ctor : & Constructor < ' tcx > ,
597481 ctor_wild_subpatterns : & Fields < ' p , ' tcx > ,
598482 ) -> 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 ( )
649488 }
650489}
651490
@@ -2442,8 +2281,7 @@ crate fn is_useful<'p, 'tcx>(
24422281 // We cache the result of `Fields::wildcards` because it is used a lot.
24432282 let ctor_wild_subpatterns = Fields :: wildcards ( pcx, & ctor) ;
24442283 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) ;
24472285 let usefulness =
24482286 is_useful ( pcx. cx , & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
24492287 usefulness. apply_constructor ( pcx, & ctor, & ctor_wild_subpatterns, is_top_level)
0 commit comments