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