@@ -564,21 +564,21 @@ enum Usefulness<'tcx> {
564564 NoWitnesses { useful : bool } ,
565565 /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
566566 /// pattern is unreachable.
567- WithWitnesses ( Vec < WitnessStack < ' tcx > > ) ,
567+ WithWitnesses ( WitnessMatrix < ' tcx > ) ,
568568}
569569
570570impl < ' tcx > Usefulness < ' tcx > {
571571 fn new_useful ( preference : ArmType ) -> Self {
572572 match preference {
573573 // A single (empty) witness of reachability.
574- FakeExtraWildcard => WithWitnesses ( vec ! [ WitnessStack ( vec! [ ] ) ] ) ,
574+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: unit_witness ( ) ) ,
575575 RealArm => NoWitnesses { useful : true } ,
576576 }
577577 }
578578
579579 fn new_not_useful ( preference : ArmType ) -> Self {
580580 match preference {
581- FakeExtraWildcard => WithWitnesses ( vec ! [ ] ) ,
581+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: empty ( ) ) ,
582582 RealArm => NoWitnesses { useful : false } ,
583583 }
584584 }
@@ -607,53 +607,16 @@ impl<'tcx> Usefulness<'tcx> {
607607 /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
608608 /// with the results of specializing with the other constructors.
609609 fn apply_constructor (
610- self ,
610+ mut self ,
611611 pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
612612 matrix : & Matrix < ' _ , ' tcx > , // used to compute missing ctors
613613 ctor : & Constructor < ' tcx > ,
614614 ) -> Self {
615- match self {
616- NoWitnesses { .. } => self ,
617- WithWitnesses ( ref witnesses) if witnesses. is_empty ( ) => self ,
618- WithWitnesses ( witnesses) => {
619- let new_witnesses = if let Constructor :: Missing { .. } = ctor {
620- let mut missing = ConstructorSet :: for_ty ( pcx. cx , pcx. ty )
621- . compute_missing ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
622- if missing. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
623- // We only report `_` here; listing other constructors would be redundant.
624- missing = vec ! [ Constructor :: NonExhaustive ] ;
625- }
626-
627- // We got the special `Missing` constructor, so each of the missing constructors
628- // gives a new pattern that is not caught by the match.
629- // We construct for each missing constructor a version of this constructor with
630- // wildcards for fields, i.e. that matches everything that can be built with it.
631- // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get
632- // the pattern `Some(_)`.
633- let new_patterns: Vec < WitnessPat < ' _ > > = missing
634- . into_iter ( )
635- . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( pcx, missing_ctor. clone ( ) ) )
636- . collect ( ) ;
637-
638- witnesses
639- . into_iter ( )
640- . flat_map ( |witness| {
641- new_patterns. iter ( ) . map ( move |pat| {
642- let mut stack = witness. clone ( ) ;
643- stack. 0 . push ( pat. clone ( ) ) ;
644- stack
645- } )
646- } )
647- . collect ( )
648- } else {
649- witnesses
650- . into_iter ( )
651- . map ( |witness| witness. apply_constructor ( pcx, ctor) )
652- . collect ( )
653- } ;
654- WithWitnesses ( new_witnesses)
655- }
615+ match & mut self {
616+ NoWitnesses { .. } => { }
617+ WithWitnesses ( witnesses) => witnesses. apply_constructor ( pcx, matrix, ctor) ,
656618 }
619+ self
657620 }
658621}
659622
@@ -663,9 +626,9 @@ enum ArmType {
663626 RealArm ,
664627}
665628
666- /// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in
667- /// reverse order of construction) with wildcards inside to represent elements that can take any
668- /// inhabitant of the type as a value.
629+ /// A partially-constructed witness of non-exhaustiveness for error reporting, represented as a list
630+ /// of patterns (in reverse order of construction) with wildcards inside to represent elements that
631+ /// can take any inhabitant of the type as a value.
669632///
670633/// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we
671634/// are inspecting, and `WitnessStack` contains witnesses we are constructing.
@@ -723,30 +686,104 @@ impl<'tcx> WitnessStack<'tcx> {
723686 self . 0 . into_iter ( ) . next ( ) . unwrap ( )
724687 }
725688
726- /// Constructs a partial witness for a pattern given a list of
727- /// patterns expanded by the specialization step.
728- ///
729- /// When a pattern P is discovered to be useful, this function is used bottom-up
730- /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
731- /// of values, V, where each value in that set is not covered by any previously
732- /// used patterns and is covered by the pattern P' . Examples:
689+ /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
690+ fn push_pattern ( & mut self , pat : WitnessPat < ' tcx > ) {
691+ self . 0 . push ( pat ) ;
692+ }
693+
694+ /// Reverses specialization. Given a witness obtained after specialization, this constructs a
695+ /// new witness valid for before specialization . Examples:
733696 ///
734- /// left_ty: tuple of 3 elements
735- /// pats: [10, 20, _] => (10, 20, _)
697+ /// ctor: tuple of 2 elements
698+ /// pats: [false, "foo", _, true]
699+ /// result: [(false, "foo"), _, true]
736700 ///
737- /// left_ty: struct X { a: (bool, &'static str), b: usize}
738- /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
739- fn apply_constructor ( mut self , pcx : & PatCtxt < ' _ , ' _ , ' tcx > , ctor : & Constructor < ' tcx > ) -> Self {
740- let pat = {
741- let len = self . 0 . len ( ) ;
742- let arity = ctor. arity ( pcx) ;
743- let fields = self . 0 . drain ( ( len - arity) ..) . rev ( ) . collect ( ) ;
744- WitnessPat :: new ( ctor. clone ( ) , fields, pcx. ty )
745- } ;
746-
701+ /// ctor: Enum::Variant { a: (bool, &'static str), b: usize}
702+ /// pats: [(false, "foo"), _, true]
703+ /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true]
704+ fn apply_constructor ( & mut self , pcx : & PatCtxt < ' _ , ' _ , ' tcx > , ctor : & Constructor < ' tcx > ) {
705+ let len = self . 0 . len ( ) ;
706+ let arity = ctor. arity ( pcx) ;
707+ let fields = self . 0 . drain ( ( len - arity) ..) . rev ( ) . collect ( ) ;
708+ let pat = WitnessPat :: new ( ctor. clone ( ) , fields, pcx. ty ) ;
747709 self . 0 . push ( pat) ;
710+ }
711+ }
748712
749- self
713+ /// Represents a set of partially-constructed witnesses of non-exhaustiveness for error reporting.
714+ /// This has similar invariants as `Matrix` does.
715+ /// Throughout the exhaustiveness phase of the algorithm, `is_useful` maintains the invariant that
716+ /// the union of the `Matrix` and the `WitnessMatrix` together matches the type exhaustively. By the
717+ /// end of the algorithm, this has a single column, which contains the patterns that are missing for
718+ /// the match to be exhaustive.
719+ #[ derive( Debug , Clone ) ]
720+ pub struct WitnessMatrix < ' tcx > ( Vec < WitnessStack < ' tcx > > ) ;
721+
722+ impl < ' tcx > WitnessMatrix < ' tcx > {
723+ /// New matrix with no rows.
724+ fn empty ( ) -> Self {
725+ WitnessMatrix ( vec ! [ ] )
726+ }
727+ /// New matrix with one row and no columns.
728+ fn unit_witness ( ) -> Self {
729+ WitnessMatrix ( vec ! [ WitnessStack ( vec![ ] ) ] )
730+ }
731+
732+ /// Whether this has any rows.
733+ fn is_empty ( & self ) -> bool {
734+ self . 0 . is_empty ( )
735+ }
736+ /// Asserts that there is a single column and returns the patterns in it.
737+ fn single_column ( self ) -> Vec < WitnessPat < ' tcx > > {
738+ self . 0 . into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( )
739+ }
740+
741+ /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
742+ fn push_pattern ( & mut self , pat : & WitnessPat < ' tcx > ) {
743+ for witness in self . 0 . iter_mut ( ) {
744+ witness. push_pattern ( pat. clone ( ) )
745+ }
746+ }
747+
748+ /// Reverses specialization by `ctor`.
749+ fn apply_constructor (
750+ & mut self ,
751+ pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
752+ matrix : & Matrix < ' _ , ' tcx > , // used to compute missing ctors
753+ ctor : & Constructor < ' tcx > ,
754+ ) {
755+ if self . is_empty ( ) {
756+ return ;
757+ }
758+ if matches ! ( ctor, Constructor :: Missing { .. } ) {
759+ let missing_ctors = ConstructorSet :: for_ty ( pcx. cx , pcx. ty )
760+ . compute_missing ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
761+ // We got the special `Missing` constructor, so each of the missing constructors gives a
762+ // new pattern that is not caught by the match. We list those patterns and push them
763+ // onto our current witnesses.
764+ if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
765+ // We only report `_` here; listing other constructors would be redundant.
766+ let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: NonExhaustive ) ;
767+ self . push_pattern ( & pat) ;
768+ } else {
769+ let old_witnesses = std:: mem:: replace ( self , Self :: empty ( ) ) ;
770+ for ctor in missing_ctors {
771+ let pat = WitnessPat :: wild_from_ctor ( pcx, ctor. clone ( ) ) ;
772+ let mut witnesses_with_missing_ctor = old_witnesses. clone ( ) ;
773+ witnesses_with_missing_ctor. push_pattern ( & pat) ;
774+ self . extend ( witnesses_with_missing_ctor)
775+ }
776+ }
777+ } else {
778+ for witness in self . 0 . iter_mut ( ) {
779+ witness. apply_constructor ( pcx, ctor)
780+ }
781+ }
782+ }
783+
784+ /// Merges the rows of two witness matrices. Their column types must match.
785+ fn extend ( & mut self , other : Self ) {
786+ self . 0 . extend ( other. 0 )
750787 }
751788}
752789
@@ -1144,7 +1181,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
11441181 let v = PatStack :: from_pattern ( wild_pattern) ;
11451182 let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
11461183 let non_exhaustiveness_witnesses: Vec < _ > = match usefulness {
1147- WithWitnesses ( pats ) => pats . into_iter ( ) . map ( |w| w . single_pattern ( ) ) . collect ( ) ,
1184+ WithWitnesses ( witness_matrix ) => witness_matrix . single_column ( ) ,
11481185 NoWitnesses { .. } => bug ! ( ) ,
11491186 } ;
11501187
0 commit comments