@@ -700,15 +700,16 @@ impl<'tcx> WitnessMatrix<'tcx> {
700
700
pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
701
701
missing_ctors : & [ Constructor < ' tcx > ] ,
702
702
ctor : & Constructor < ' tcx > ,
703
+ report_when_all_missing : bool ,
703
704
) {
704
705
if self . is_empty ( ) {
705
706
return ;
706
707
}
707
- if matches ! ( ctor, Constructor :: Missing { .. } ) {
708
- // We got the special `Missing` constructor, so each of the missing constructors gives a
709
- // new pattern that is not caught by the match. We list those patterns and push them
710
- // onto our current witnesses.
711
- if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
708
+ if matches ! ( ctor, Constructor :: Wildcard | Constructor :: Missing ) {
709
+ if matches ! ( ctor , Constructor :: Wildcard ) && !report_when_all_missing {
710
+ let pat = WitnessPat :: wild_from_ctor ( pcx , Constructor :: Wildcard ) ;
711
+ self . push_pattern ( & pat ) ;
712
+ } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
712
713
// We only report `_` here; listing other constructors would be redundant.
713
714
let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: NonExhaustive ) ;
714
715
self . push_pattern ( & pat) ;
@@ -722,8 +723,17 @@ impl<'tcx> WitnessMatrix<'tcx> {
722
723
}
723
724
}
724
725
} else {
725
- for witness in self . 0 . iter_mut ( ) {
726
- witness. apply_constructor ( pcx, ctor)
726
+ // We have a non-wildcard constructor.
727
+ if !missing_ctors. is_empty ( ) {
728
+ // If some ctors are missing we want to only report them (so we discard non-missing
729
+ // ones). This is guaranteed to report *some* witnesses because
730
+ // `!missing_ctors.is_empty()` implies there is a `Missing` or `Wildcard` in
731
+ // `split_ctors`.
732
+ * self = Self :: new_empty ( ) ;
733
+ } else {
734
+ for witness in self . 0 . iter_mut ( ) {
735
+ witness. apply_constructor ( pcx, ctor)
736
+ }
727
737
}
728
738
}
729
739
}
@@ -760,7 +770,6 @@ impl<'tcx> WitnessMatrix<'tcx> {
760
770
fn compute_usefulness < ' p , ' tcx > (
761
771
cx : & MatchCheckCtxt < ' p , ' tcx > ,
762
772
matrix : & mut Matrix < ' p , ' tcx > ,
763
- collect_witnesses : bool ,
764
773
lint_root : HirId ,
765
774
is_top_level : bool ,
766
775
) -> WitnessMatrix < ' tcx > {
@@ -777,7 +786,7 @@ fn compute_usefulness<'p, 'tcx>(
777
786
break ;
778
787
}
779
788
}
780
- if useful && collect_witnesses {
789
+ if useful {
781
790
return WitnessMatrix :: new_unit ( ) ;
782
791
} else {
783
792
return WitnessMatrix :: new_empty ( ) ;
@@ -792,59 +801,17 @@ fn compute_usefulness<'p, 'tcx>(
792
801
let split_set = ConstructorSet :: for_ty ( pcx. cx , pcx. ty ) . split ( pcx, ctors, is_top_level) ;
793
802
let mut split_ctors = split_set. present ;
794
803
let missing_ctors = split_set. missing ;
804
+ // We want to iterate over a full set of constructors, so if any is missing we add a wildcard.
795
805
if !missing_ctors. is_empty ( ) {
796
- // We are splitting a wildcard in order to compute its usefulness. Some constructors are
797
- // not present in the column. The first thing we note is that specializing with any of
798
- // the missing constructors would select exactly the rows with wildcards. Moreover, they
799
- // would all return equivalent results. We can therefore group them all into a
800
- // fictitious `Missing` constructor.
801
- //
802
- // As an important optimization, this function will skip all the present constructors.
803
- // This is correct because specializing with any of the present constructors would
804
- // select a strict superset of the wildcard rows, and thus would only find witnesses
805
- // already found with the `Missing` constructor.
806
- // This does mean that diagnostics are incomplete: in
807
- // ```
808
- // match x {
809
- // Some(true) => {}
810
- // }
811
- // ```
812
- // we report `None` as missing but not `Some(false)`.
813
- //
814
- // When all the constructors are missing we can equivalently return the `Wildcard`
815
- // constructor on its own. The difference between `Wildcard` and `Missing` will then
816
- // only be in diagnostics.
817
-
818
- // If some constructors are missing, we typically want to report those constructors,
819
- // e.g.:
820
- // ```
821
- // enum Direction { N, S, E, W }
822
- // let Direction::N = ...;
823
- // ```
824
- // we can report 3 witnesses: `S`, `E`, and `W`.
825
- //
826
- // However, if the user didn't actually specify a constructor
827
- // in this arm, e.g., in
828
- // ```
829
- // let x: (Direction, Direction, bool) = ...;
830
- // let (_, _, false) = x;
831
- // ```
832
- // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
833
- // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
834
- // prefer to report just a wildcard `_`.
835
- //
836
- // The exception is: if we are at the top-level, for example in an empty match, we
837
- // usually prefer to report the full list of constructors.
838
- let all_missing = split_ctors. is_empty ( ) ;
839
- let report_when_all_missing =
840
- is_top_level && !super :: deconstruct_pat:: IntRange :: is_integral ( pcx. ty ) ;
841
- let ctor = if all_missing && !report_when_all_missing {
842
- Constructor :: Wildcard
806
+ if split_ctors. is_empty ( ) {
807
+ split_ctors. push ( Constructor :: Wildcard ) ;
843
808
} else {
844
- Constructor :: Missing
845
- } ;
846
- split_ctors. push ( ctor) ;
809
+ split_ctors. push ( Constructor :: Missing ) ;
810
+ }
847
811
}
812
+ // At the top level, we prefer to list all constructors when `_` could be reported as missing.
813
+ let report_when_all_missing =
814
+ is_top_level && !super :: deconstruct_pat:: IntRange :: is_integral ( pcx. ty ) ;
848
815
849
816
if super :: deconstruct_pat:: IntRange :: is_integral ( ty) {
850
817
for row_id in 0 ..matrix. len ( ) {
@@ -874,20 +841,12 @@ fn compute_usefulness<'p, 'tcx>(
874
841
// witness the usefulness of `v`.
875
842
let mut ret = WitnessMatrix :: new_empty ( ) ;
876
843
for ctor in split_ctors {
877
- // If some ctors are missing we only report those. Could report all if that's useful for
878
- // some applications.
879
- let collect_witnesses = collect_witnesses
880
- && ( missing_ctors. is_empty ( )
881
- || matches ! ( ctor, Constructor :: Wildcard | Constructor :: Missing ) ) ;
882
844
debug ! ( "specialize({:?})" , ctor) ;
883
845
let mut spec_matrix = matrix. specialize_constructor ( pcx, & ctor) ;
884
- let mut witnesses = ensure_sufficient_stack ( || {
885
- compute_usefulness ( cx, & mut spec_matrix, collect_witnesses, lint_root, false )
886
- } ) ;
887
- if collect_witnesses {
888
- witnesses. apply_constructor ( pcx, & missing_ctors, & ctor) ;
889
- ret. extend ( witnesses) ;
890
- }
846
+ let mut witnesses =
847
+ ensure_sufficient_stack ( || compute_usefulness ( cx, & mut spec_matrix, lint_root, false ) ) ;
848
+ witnesses. apply_constructor ( pcx, & missing_ctors, & ctor, report_when_all_missing) ;
849
+ ret. extend ( witnesses) ;
891
850
892
851
for child_row in spec_matrix. rows ( ) {
893
852
let parent_row = & mut matrix. rows [ child_row. parent_row ] ;
@@ -1028,7 +987,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
1028
987
matrix. push ( v) ;
1029
988
}
1030
989
1031
- let non_exhaustiveness_witnesses = compute_usefulness ( cx, & mut matrix, true , lint_root, true ) ;
990
+ let non_exhaustiveness_witnesses = compute_usefulness ( cx, & mut matrix, lint_root, true ) ;
1032
991
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1033
992
let arm_usefulness: Vec < _ > = arms
1034
993
. iter ( )
0 commit comments