@@ -559,21 +559,21 @@ enum Usefulness<'tcx> {
559
559
NoWitnesses { useful : bool } ,
560
560
/// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
561
561
/// pattern is unreachable.
562
- WithWitnesses ( Vec < WitnessStack < ' tcx > > ) ,
562
+ WithWitnesses ( WitnessMatrix < ' tcx > ) ,
563
563
}
564
564
565
565
impl < ' tcx > Usefulness < ' tcx > {
566
566
fn new_useful ( preference : ArmType ) -> Self {
567
567
match preference {
568
568
// A single (empty) witness of reachability.
569
- FakeExtraWildcard => WithWitnesses ( vec ! [ WitnessStack ( vec! [ ] ) ] ) ,
569
+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: unit_witness ( ) ) ,
570
570
RealArm => NoWitnesses { useful : true } ,
571
571
}
572
572
}
573
573
574
574
fn new_not_useful ( preference : ArmType ) -> Self {
575
575
match preference {
576
- FakeExtraWildcard => WithWitnesses ( vec ! [ ] ) ,
576
+ FakeExtraWildcard => WithWitnesses ( WitnessMatrix :: empty ( ) ) ,
577
577
RealArm => NoWitnesses { useful : false } ,
578
578
}
579
579
}
@@ -602,53 +602,16 @@ impl<'tcx> Usefulness<'tcx> {
602
602
/// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
603
603
/// with the results of specializing with the other constructors.
604
604
fn apply_constructor (
605
- self ,
605
+ mut self ,
606
606
pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
607
607
matrix : & Matrix < ' _ , ' tcx > , // used to compute missing ctors
608
608
ctor : & Constructor < ' tcx > ,
609
609
) -> Self {
610
- match self {
611
- NoWitnesses { .. } => self ,
612
- WithWitnesses ( ref witnesses) if witnesses. is_empty ( ) => self ,
613
- WithWitnesses ( witnesses) => {
614
- let new_witnesses = if let Constructor :: Missing { .. } = ctor {
615
- let mut missing = ConstructorSet :: for_ty ( pcx. cx , pcx. ty )
616
- . compute_missing ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
617
- if missing. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
618
- // We only report `_` here; listing other constructors would be redundant.
619
- missing = vec ! [ Constructor :: NonExhaustive ] ;
620
- }
621
-
622
- // We got the special `Missing` constructor, so each of the missing constructors
623
- // gives a new pattern that is not caught by the match.
624
- // We construct for each missing constructor a version of this constructor with
625
- // wildcards for fields, i.e. that matches everything that can be built with it.
626
- // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get
627
- // the pattern `Some(_)`.
628
- let new_patterns: Vec < WitnessPat < ' _ > > = missing
629
- . into_iter ( )
630
- . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( pcx, missing_ctor. clone ( ) ) )
631
- . collect ( ) ;
632
-
633
- witnesses
634
- . into_iter ( )
635
- . flat_map ( |witness| {
636
- new_patterns. iter ( ) . map ( move |pat| {
637
- let mut stack = witness. clone ( ) ;
638
- stack. 0 . push ( pat. clone ( ) ) ;
639
- stack
640
- } )
641
- } )
642
- . collect ( )
643
- } else {
644
- witnesses
645
- . into_iter ( )
646
- . map ( |witness| witness. apply_constructor ( pcx, & ctor) )
647
- . collect ( )
648
- } ;
649
- WithWitnesses ( new_witnesses)
650
- }
610
+ match & mut self {
611
+ NoWitnesses { .. } => { }
612
+ WithWitnesses ( witnesses) => witnesses. apply_constructor ( pcx, matrix, ctor) ,
651
613
}
614
+ self
652
615
}
653
616
}
654
617
@@ -658,9 +621,9 @@ enum ArmType {
658
621
RealArm ,
659
622
}
660
623
661
- /// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in
662
- /// reverse order of construction) with wildcards inside to represent elements that can take any
663
- /// inhabitant of the type as a value.
624
+ /// A partially-constructed witness of non-exhaustiveness for error reporting, represented as a list
625
+ /// of patterns (in reverse order of construction) with wildcards inside to represent elements that
626
+ /// can take any inhabitant of the type as a value.
664
627
///
665
628
/// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we
666
629
/// are inspecting, and `WitnessStack` contains witnesses we are constructing.
@@ -718,30 +681,104 @@ impl<'tcx> WitnessStack<'tcx> {
718
681
self . 0 . into_iter ( ) . next ( ) . unwrap ( )
719
682
}
720
683
721
- /// Constructs a partial witness for a pattern given a list of
722
- /// patterns expanded by the specialization step.
723
- ///
724
- /// When a pattern P is discovered to be useful, this function is used bottom-up
725
- /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
726
- /// of values, V, where each value in that set is not covered by any previously
727
- /// used patterns and is covered by the pattern P' . Examples:
684
+ /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
685
+ fn push_pattern ( & mut self , pat : WitnessPat < ' tcx > ) {
686
+ self . 0 . push ( pat ) ;
687
+ }
688
+
689
+ /// Reverses specialization. Given a witness obtained after specialization, this constructs a
690
+ /// new witness valid for before specialization . Examples:
728
691
///
729
- /// left_ty: tuple of 3 elements
730
- /// pats: [10, 20, _] => (10, 20, _)
692
+ /// ctor: tuple of 2 elements
693
+ /// pats: [false, "foo", _, true]
694
+ /// result: [(false, "foo"), _, true]
731
695
///
732
- /// left_ty: struct X { a: (bool, &'static str), b: usize}
733
- /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
734
- fn apply_constructor ( mut self , pcx : & PatCtxt < ' _ , ' _ , ' tcx > , ctor : & Constructor < ' tcx > ) -> Self {
735
- let pat = {
736
- let len = self . 0 . len ( ) ;
737
- let arity = ctor. arity ( pcx) ;
738
- let fields = self . 0 . drain ( ( len - arity) ..) . rev ( ) . collect ( ) ;
739
- WitnessPat :: new ( ctor. clone ( ) , fields, pcx. ty )
740
- } ;
741
-
696
+ /// ctor: Enum::Variant { a: (bool, &'static str), b: usize}
697
+ /// pats: [(false, "foo"), _, true]
698
+ /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true]
699
+ fn apply_constructor ( & mut self , pcx : & PatCtxt < ' _ , ' _ , ' tcx > , ctor : & Constructor < ' tcx > ) {
700
+ let len = self . 0 . len ( ) ;
701
+ let arity = ctor. arity ( pcx) ;
702
+ let fields = self . 0 . drain ( ( len - arity) ..) . rev ( ) . collect ( ) ;
703
+ let pat = WitnessPat :: new ( ctor. clone ( ) , fields, pcx. ty ) ;
742
704
self . 0 . push ( pat) ;
705
+ }
706
+ }
743
707
744
- self
708
+ /// Represents a set of partially-constructed witnesses of non-exhaustiveness for error reporting.
709
+ /// This has similar invariants as `Matrix` does.
710
+ /// Throughout the exhaustiveness phase of the algorithm, `is_useful` maintains the invariant that
711
+ /// the union of the `Matrix` and the `WitnessMatrix` together matches the type exhaustively. By the
712
+ /// end of the algorithm, this has a single column, which contains the patterns that are missing for
713
+ /// the match to be exhaustive.
714
+ #[ derive( Debug , Clone ) ]
715
+ pub struct WitnessMatrix < ' tcx > ( Vec < WitnessStack < ' tcx > > ) ;
716
+
717
+ impl < ' tcx > WitnessMatrix < ' tcx > {
718
+ /// New matrix with no rows.
719
+ fn empty ( ) -> Self {
720
+ WitnessMatrix ( vec ! [ ] )
721
+ }
722
+ /// New matrix with one row and no columns.
723
+ fn unit_witness ( ) -> Self {
724
+ WitnessMatrix ( vec ! [ WitnessStack ( vec![ ] ) ] )
725
+ }
726
+
727
+ /// Whether this has any rows.
728
+ fn is_empty ( & self ) -> bool {
729
+ self . 0 . is_empty ( )
730
+ }
731
+ /// Asserts that there is a single column and returns the patterns in it.
732
+ fn single_column ( self ) -> Vec < WitnessPat < ' tcx > > {
733
+ self . 0 . into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( )
734
+ }
735
+
736
+ /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
737
+ fn push_pattern ( & mut self , pat : & WitnessPat < ' tcx > ) {
738
+ for witness in self . 0 . iter_mut ( ) {
739
+ witness. push_pattern ( pat. clone ( ) )
740
+ }
741
+ }
742
+
743
+ /// Reverses specialization by `ctor`.
744
+ fn apply_constructor (
745
+ & mut self ,
746
+ pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
747
+ matrix : & Matrix < ' _ , ' tcx > , // used to compute missing ctors
748
+ ctor : & Constructor < ' tcx > ,
749
+ ) {
750
+ if self . is_empty ( ) {
751
+ return ;
752
+ }
753
+ if matches ! ( ctor, Constructor :: Missing { .. } ) {
754
+ let missing_ctors = ConstructorSet :: for_ty ( pcx. cx , pcx. ty )
755
+ . compute_missing ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
756
+ // We got the special `Missing` constructor, so each of the missing constructors gives a
757
+ // new pattern that is not caught by the match. We list those patterns and push them
758
+ // onto our current witnesses.
759
+ if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
760
+ // We only report `_` here; listing other constructors would be redundant.
761
+ let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: NonExhaustive ) ;
762
+ self . push_pattern ( & pat) ;
763
+ } else {
764
+ let old_witnesses = std:: mem:: replace ( self , Self :: empty ( ) ) ;
765
+ for ctor in missing_ctors {
766
+ let pat = WitnessPat :: wild_from_ctor ( pcx, ctor. clone ( ) ) ;
767
+ let mut witnesses_with_missing_ctor = old_witnesses. clone ( ) ;
768
+ witnesses_with_missing_ctor. push_pattern ( & pat) ;
769
+ self . extend ( witnesses_with_missing_ctor)
770
+ }
771
+ }
772
+ } else {
773
+ for witness in self . 0 . iter_mut ( ) {
774
+ witness. apply_constructor ( pcx, ctor)
775
+ }
776
+ }
777
+ }
778
+
779
+ /// Merges the rows of two witness matrices. Their column types must match.
780
+ fn extend ( & mut self , other : Self ) {
781
+ self . 0 . extend ( other. 0 )
745
782
}
746
783
}
747
784
@@ -1139,7 +1176,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1139
1176
let v = PatStack :: from_pattern ( wild_pattern) ;
1140
1177
let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
1141
1178
let non_exhaustiveness_witnesses: Vec < _ > = match usefulness {
1142
- WithWitnesses ( pats ) => pats . into_iter ( ) . map ( |w| w . single_pattern ( ) ) . collect ( ) ,
1179
+ WithWitnesses ( witness_matrix ) => witness_matrix . single_column ( ) ,
1143
1180
NoWitnesses { .. } => bug ! ( ) ,
1144
1181
} ;
1145
1182
0 commit comments