@@ -607,6 +607,9 @@ pub(super) enum Constructor<'tcx> {
607
607
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
608
608
/// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
609
609
NonExhaustive ,
610
+ /// Stands for constructors that are not seen in the matrix, as explained in the documentation
611
+ /// for [`SplitWildcard`].
612
+ Missing ,
610
613
/// Wildcard pattern.
611
614
Wildcard ,
612
615
}
@@ -758,8 +761,8 @@ impl<'tcx> Constructor<'tcx> {
758
761
match ( self , other) {
759
762
// Wildcards cover anything
760
763
( _, Wildcard ) => true ,
761
- // Wildcards are only covered by wildcards
762
- ( Wildcard , _) => false ,
764
+ // The missing ctors are not covered by anything in the matrix except wildcards.
765
+ ( Missing | Wildcard , _) => false ,
763
766
764
767
( Single , Single ) => true ,
765
768
( Variant ( self_id) , Variant ( other_id) ) => self_id == other_id,
@@ -832,7 +835,7 @@ impl<'tcx> Constructor<'tcx> {
832
835
. any ( |other| slice. is_covered_by ( other) ) ,
833
836
// This constructor is never covered by anything else
834
837
NonExhaustive => false ,
835
- Str ( ..) | FloatRange ( ..) | Opaque | Wildcard => {
838
+ Str ( ..) | FloatRange ( ..) | Opaque | Missing | Wildcard => {
836
839
span_bug ! ( pcx. span, "found unexpected ctor in all_ctors: {:?}" , self )
837
840
}
838
841
}
@@ -1002,7 +1005,7 @@ impl<'tcx> SplitWildcard<'tcx> {
1002
1005
}
1003
1006
1004
1007
/// Iterate over the constructors for this type that are not present in the matrix.
1005
- fn iter_missing < ' a , ' p > (
1008
+ pub ( super ) fn iter_missing < ' a , ' p > (
1006
1009
& ' a self ,
1007
1010
pcx : PatCtxt < ' a , ' p , ' tcx > ,
1008
1011
) -> impl Iterator < Item = & ' a Constructor < ' tcx > > + Captures < ' p > {
@@ -1013,64 +1016,45 @@ impl<'tcx> SplitWildcard<'tcx> {
1013
1016
/// top of the file, if any constructors are missing we can ignore the present ones.
1014
1017
fn into_ctors ( self , pcx : PatCtxt < ' _ , ' _ , ' tcx > ) -> SmallVec < [ Constructor < ' tcx > ; 1 ] > {
1015
1018
if self . any_missing ( pcx) {
1016
- // Some constructors are missing, thus we can specialize with the wildcard constructor,
1017
- // which will stand for those constructors that are missing, and matches the same rows
1018
- // as any of them (namely the wildcard rows).
1019
- return smallvec ! [ Wildcard ] ;
1019
+ // Some constructors are missing, thus we can specialize with the special `Missing`
1020
+ // constructor, which stands for those constructors that are not seen in the matrix,
1021
+ // and matches the same rows as any of them (namely the wildcard rows). See the top of
1022
+ // the file for details.
1023
+ // However, when all constructors are missing we can also specialize with the full
1024
+ // `Wildcard` constructor. The difference will depend on what we want in diagnostics.
1025
+
1026
+ // If some constructors are missing, we typically want to report those constructors,
1027
+ // e.g.:
1028
+ // ```
1029
+ // enum Direction { N, S, E, W }
1030
+ // let Direction::N = ...;
1031
+ // ```
1032
+ // we can report 3 witnesses: `S`, `E`, and `W`.
1033
+ //
1034
+ // However, if the user didn't actually specify a constructor
1035
+ // in this arm, e.g., in
1036
+ // ```
1037
+ // let x: (Direction, Direction, bool) = ...;
1038
+ // let (_, _, false) = x;
1039
+ // ```
1040
+ // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
1041
+ // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
1042
+ // prefer to report just a wildcard `_`.
1043
+ //
1044
+ // The exception is: if we are at the top-level, for example in an empty match, we
1045
+ // sometimes prefer reporting the list of constructors instead of just `_`.
1046
+ let report_when_all_missing = pcx. is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
1047
+ let ctor = if !self . matrix_ctors . is_empty ( ) || report_when_all_missing {
1048
+ Missing
1049
+ } else {
1050
+ Wildcard
1051
+ } ;
1052
+ return smallvec ! [ ctor] ;
1020
1053
}
1021
1054
1022
1055
// All the constructors are present in the matrix, so we just go through them all.
1023
1056
self . all_ctors
1024
1057
}
1025
-
1026
- /// List the patterns corresponding to the missing constructors. In some cases, instead of
1027
- /// listing all constructors of a given type, we prefer to simply report a wildcard.
1028
- pub ( super ) fn report_missing_patterns < ' p > (
1029
- & self ,
1030
- pcx : PatCtxt < ' _ , ' p , ' tcx > ,
1031
- ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
1032
- // There are 2 ways we can report a witness here.
1033
- // Commonly, we can report all the "free"
1034
- // constructors as witnesses, e.g., if we have:
1035
- //
1036
- // ```
1037
- // enum Direction { N, S, E, W }
1038
- // let Direction::N = ...;
1039
- // ```
1040
- //
1041
- // we can report 3 witnesses: `S`, `E`, and `W`.
1042
- //
1043
- // However, there is a case where we don't want
1044
- // to do this and instead report a single `_` witness:
1045
- // if the user didn't actually specify a constructor
1046
- // in this arm, e.g., in
1047
- //
1048
- // ```
1049
- // let x: (Direction, Direction, bool) = ...;
1050
- // let (_, _, false) = x;
1051
- // ```
1052
- //
1053
- // we don't want to show all 16 possible witnesses
1054
- // `(<direction-1>, <direction-2>, true)` - we are
1055
- // satisfied with `(_, _, true)`. In this case,
1056
- // `used_ctors` is empty.
1057
- // The exception is: if we are at the top-level, for example in an empty match, we
1058
- // sometimes prefer reporting the list of constructors instead of just `_`.
1059
- let report_when_all_missing = pcx. is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
1060
- if self . matrix_ctors . is_empty ( ) && !report_when_all_missing {
1061
- // All constructors are unused. Report only a wildcard
1062
- // rather than each individual constructor.
1063
- smallvec ! [ Pat :: wildcard_from_ty( pcx. ty) ]
1064
- } else {
1065
- // Construct for each missing constructor a "wild" version of this
1066
- // constructor, that matches everything that can be built with
1067
- // it. For example, if `ctor` is a `Constructor::Variant` for
1068
- // `Option::Some`, we get the pattern `Some(_)`.
1069
- self . iter_missing ( pcx)
1070
- . map ( |missing_ctor| Fields :: wildcards ( pcx, & missing_ctor) . apply ( pcx, missing_ctor) )
1071
- . collect ( )
1072
- }
1073
- }
1074
1058
}
1075
1059
1076
1060
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
@@ -1211,9 +1195,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1211
1195
}
1212
1196
_ => bug ! ( "bad slice pattern {:?} {:?}" , constructor, ty) ,
1213
1197
} ,
1214
- Str ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive | Opaque | Wildcard => {
1215
- Fields :: empty ( )
1216
- }
1198
+ Str ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive | Opaque | Missing
1199
+ | Wildcard => Fields :: empty ( ) ,
1217
1200
} ;
1218
1201
debug ! ( "Fields::wildcards({:?}, {:?}) = {:#?}" , constructor, ty, ret) ;
1219
1202
ret
@@ -1297,9 +1280,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1297
1280
& FloatRange ( lo, hi, end) => PatKind :: Range ( PatRange { lo, hi, end } ) ,
1298
1281
IntRange ( range) => return range. to_pat ( pcx. cx . tcx , pcx. ty ) ,
1299
1282
NonExhaustive => PatKind :: Wild ,
1283
+ Wildcard => return Pat :: wildcard_from_ty ( pcx. ty ) ,
1300
1284
Opaque => bug ! ( "we should not try to apply an opaque constructor" ) ,
1301
- Wildcard => bug ! (
1302
- "trying to apply a wildcard constructor; this should have been done in `apply_constructors`"
1285
+ Missing => bug ! (
1286
+ "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`"
1303
1287
) ,
1304
1288
} ;
1305
1289
0 commit comments