@@ -564,21 +564,21 @@ enum Usefulness<'tcx> {
564
564
NoWitnesses { useful : bool } ,
565
565
/// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
566
566
/// pattern is unreachable.
567
- WithWitnesses ( Vec < WitnessStack < ' tcx > > ) ,
567
+ WithWitnesses ( WitnessMatrix < ' tcx > ) ,
568
568
}
569
569
570
570
impl < ' tcx > Usefulness < ' tcx > {
571
571
fn new_useful ( preference : ArmType ) -> Self {
572
572
match preference {
573
573
// A single (empty) witness of reachability.
574
- FakeExtraWildcard => WithWitnesses ( vec ! [ WitnessStack ( vec! [ ] ) ] ) ,
574
+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: unit_witness ( ) ) ,
575
575
RealArm => NoWitnesses { useful : true } ,
576
576
}
577
577
}
578
578
579
579
fn new_not_useful ( preference : ArmType ) -> Self {
580
580
match preference {
581
- FakeExtraWildcard => WithWitnesses ( vec ! [ ] ) ,
581
+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: empty ( ) ) ,
582
582
RealArm => NoWitnesses { useful : false } ,
583
583
}
584
584
}
@@ -607,53 +607,16 @@ impl<'tcx> Usefulness<'tcx> {
607
607
/// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
608
608
/// with the results of specializing with the other constructors.
609
609
fn apply_constructor (
610
- self ,
610
+ mut self ,
611
611
pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
612
612
matrix : & Matrix < ' _ , ' tcx > , // used to compute missing ctors
613
613
ctor : & Constructor < ' tcx > ,
614
614
) -> 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) ,
656
618
}
619
+ self
657
620
}
658
621
}
659
622
@@ -663,9 +626,9 @@ enum ArmType {
663
626
RealArm ,
664
627
}
665
628
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.
669
632
///
670
633
/// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we
671
634
/// are inspecting, and `WitnessStack` contains witnesses we are constructing.
@@ -723,30 +686,104 @@ impl<'tcx> WitnessStack<'tcx> {
723
686
self . 0 . into_iter ( ) . next ( ) . unwrap ( )
724
687
}
725
688
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:
733
696
///
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]
736
700
///
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 ) ;
747
709
self . 0 . push ( pat) ;
710
+ }
711
+ }
748
712
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 )
750
787
}
751
788
}
752
789
@@ -1144,7 +1181,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1144
1181
let v = PatStack :: from_pattern ( wild_pattern) ;
1145
1182
let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
1146
1183
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 ( ) ,
1148
1185
NoWitnesses { .. } => bug ! ( ) ,
1149
1186
} ;
1150
1187
0 commit comments