@@ -928,7 +928,7 @@ impl<'tcx> WitnessMatrix<'tcx> {
928
928
}
929
929
930
930
/// Reverses specialization by the `Missing` constructor by pushing a whole new pattern.
931
- fn push_pattern ( & mut self , pat : & WitnessPat < ' tcx > ) {
931
+ fn push_pattern ( & mut self , pat : WitnessPat < ' tcx > ) {
932
932
for witness in self . 0 . iter_mut ( ) {
933
933
witness. push_pattern ( pat. clone ( ) )
934
934
}
@@ -940,37 +940,39 @@ impl<'tcx> WitnessMatrix<'tcx> {
940
940
pcx : & PatCtxt < ' _ , ' _ , ' tcx > ,
941
941
missing_ctors : & [ Constructor < ' tcx > ] ,
942
942
ctor : & Constructor < ' tcx > ,
943
+ report_individual_missing_ctors : bool ,
943
944
) {
944
945
if self . is_empty ( ) {
945
946
return ;
946
947
}
947
- if matches ! ( ctor, Constructor :: Wildcard ) {
948
- let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: Wildcard ) ;
949
- self . push_pattern ( & pat) ;
950
- } else if matches ! ( ctor, Constructor :: Missing ) {
951
- // We got the special `Missing` constructor, so each of the missing constructors gives a
952
- // new pattern that is not caught by the match. We list those patterns and push them
953
- // onto our current witnesses.
954
- if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
955
- // We only report `_` here; listing other constructors would be redundant.
948
+ if matches ! ( ctor, Constructor :: Missing ) {
949
+ // We got the special `Missing` constructor that stands for the constructors not present
950
+ // in the match.
951
+ if !report_individual_missing_ctors {
952
+ // Report `_` as missing.
953
+ let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: Wildcard ) ;
954
+ self . push_pattern ( pat) ;
955
+ } else if missing_ctors. iter ( ) . any ( |c| c. is_non_exhaustive ( ) ) {
956
+ // We need to report a `_` anyway, so listing other constructors would be redundant.
957
+ // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
958
+ // up by diagnostics to add a note about why `_` is required here.
956
959
let pat = WitnessPat :: wild_from_ctor ( pcx, Constructor :: NonExhaustive ) ;
957
- self . push_pattern ( & pat) ;
960
+ self . push_pattern ( pat) ;
958
961
} else {
959
- let old_witnesses = std:: mem:: replace ( self , Self :: empty ( ) ) ;
962
+ // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately
963
+ // filled with wildcards.
964
+ let mut ret = Self :: empty ( ) ;
960
965
for ctor in missing_ctors {
961
966
let pat = WitnessPat :: wild_from_ctor ( pcx, ctor. clone ( ) ) ;
962
- let mut witnesses_with_missing_ctor = old_witnesses. clone ( ) ;
963
- witnesses_with_missing_ctor. push_pattern ( & pat) ;
964
- self . extend ( witnesses_with_missing_ctor)
967
+ // Clone `self` and add `c(_, _, _)` to each of its witnesses.
968
+ let mut wit_matrix = self . clone ( ) ;
969
+ wit_matrix. push_pattern ( pat) ;
970
+ ret. extend ( wit_matrix) ;
965
971
}
972
+ * self = ret;
966
973
}
967
- } else if !missing_ctors. is_empty ( ) {
968
- // `ctor` isn't `Wildcard` or `Missing` and some ctors are missing, so we know
969
- // `split_ctors` will contain `Wildcard` or `Missing`.
970
- // For diagnostic purposes we choose to discard witnesses we got under `ctor`, which
971
- // will let only the `Wildcard` or `Missing` be reported.
972
- self . 0 . clear ( ) ;
973
974
} else {
975
+ // Any other constructor we unspecialize as expected.
974
976
for witness in self . 0 . iter_mut ( ) {
975
977
witness. apply_constructor ( pcx, ctor)
976
978
}
@@ -1027,19 +1029,23 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
1027
1029
// Analyze the constructors present in this column.
1028
1030
let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1029
1031
let split_set = ConstructorSet :: for_ty ( pcx. cx , pcx. ty ) . split ( pcx, ctors) ;
1032
+
1033
+ let all_missing = split_set. present . is_empty ( ) ;
1034
+ let always_report_all = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
1035
+ // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1036
+ let report_individual_missing_ctors = always_report_all || !all_missing;
1037
+
1030
1038
let mut split_ctors = split_set. present ;
1031
- // We want to iterate over a full set of constructors, so if any is missing we add a wildcard.
1039
+ let mut only_report_missing = false ;
1032
1040
if !split_set. missing . is_empty ( ) {
1033
- let all_missing = split_ctors. is_empty ( ) ;
1034
- let always_report_missing = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
1035
- let ctor = if all_missing && !always_report_missing {
1036
- Constructor :: Wildcard
1037
- } else {
1038
- // Like `Wildcard`, except if it doesn't match a row this will report all the missing
1039
- // constructors instead of just `_`.
1040
- Constructor :: Missing
1041
- } ;
1042
- split_ctors. push ( ctor) ;
1041
+ // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1042
+ // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1043
+ split_ctors. push ( Constructor :: Missing ) ;
1044
+ // For diagnostic purposes we choose to only report the constructors that are missing. Since
1045
+ // `Missing` matches only the wildcard rows, it matches fewer rows than any normal
1046
+ // constructor and is therefore guaranteed to result in more witnesses. So skipping the
1047
+ // other constructors does not jeopardize correctness.
1048
+ only_report_missing = true ;
1043
1049
}
1044
1050
1045
1051
let mut ret = WitnessMatrix :: empty ( ) ;
@@ -1050,9 +1056,18 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
1050
1056
let mut witnesses = ensure_sufficient_stack ( || {
1051
1057
compute_exhaustiveness_and_reachability ( cx, & mut spec_matrix, false )
1052
1058
} ) ;
1053
- // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1054
- witnesses. apply_constructor ( pcx, & split_set. missing , & ctor) ;
1055
- ret. extend ( witnesses) ;
1059
+
1060
+ if !only_report_missing || matches ! ( ctor, Constructor :: Missing ) {
1061
+ // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
1062
+ witnesses. apply_constructor (
1063
+ pcx,
1064
+ & split_set. missing ,
1065
+ & ctor,
1066
+ report_individual_missing_ctors,
1067
+ ) ;
1068
+ // Accumulate the found witnesses.
1069
+ ret. extend ( witnesses) ;
1070
+ }
1056
1071
1057
1072
// A parent row is useful if any of its children is.
1058
1073
for child_row in spec_matrix. rows ( ) {
@@ -1067,6 +1082,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>(
1067
1082
row. head ( ) . set_reachable ( ) ;
1068
1083
}
1069
1084
}
1085
+
1070
1086
ret
1071
1087
}
1072
1088
0 commit comments