@@ -607,6 +607,9 @@ pub(super) enum Constructor<'tcx> {
607607 /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
608608 /// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
609609 NonExhaustive ,
610+ /// Stands for constructors that are not seen in the matrix, as explained in the documentation
611+ /// for [`SplitWildcard`].
612+ Missing ,
610613 /// Wildcard pattern.
611614 Wildcard ,
612615}
@@ -758,8 +761,8 @@ impl<'tcx> Constructor<'tcx> {
758761 match ( self , other) {
759762 // Wildcards cover anything
760763 ( _, 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 ,
763766
764767 ( Single , Single ) => true ,
765768 ( Variant ( self_id) , Variant ( other_id) ) => self_id == other_id,
@@ -832,7 +835,7 @@ impl<'tcx> Constructor<'tcx> {
832835 . any ( |other| slice. is_covered_by ( other) ) ,
833836 // This constructor is never covered by anything else
834837 NonExhaustive => false ,
835- Str ( ..) | FloatRange ( ..) | Opaque | Wildcard => {
838+ Str ( ..) | FloatRange ( ..) | Opaque | Missing | Wildcard => {
836839 span_bug ! ( pcx. span, "found unexpected ctor in all_ctors: {:?}" , self )
837840 }
838841 }
@@ -1002,7 +1005,7 @@ impl<'tcx> SplitWildcard<'tcx> {
10021005 }
10031006
10041007 /// 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 > (
10061009 & ' a self ,
10071010 pcx : PatCtxt < ' a , ' p , ' tcx > ,
10081011 ) -> impl Iterator < Item = & ' a Constructor < ' tcx > > + Captures < ' p > {
@@ -1013,64 +1016,45 @@ impl<'tcx> SplitWildcard<'tcx> {
10131016 /// top of the file, if any constructors are missing we can ignore the present ones.
10141017 fn into_ctors ( self , pcx : PatCtxt < ' _ , ' _ , ' tcx > ) -> SmallVec < [ Constructor < ' tcx > ; 1 ] > {
10151018 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] ;
10201053 }
10211054
10221055 // All the constructors are present in the matrix, so we just go through them all.
10231056 self . all_ctors
10241057 }
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- }
10741058}
10751059
10761060/// 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> {
12111195 }
12121196 _ => bug ! ( "bad slice pattern {:?} {:?}" , constructor, ty) ,
12131197 } ,
1214- Str ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive | Opaque | Wildcard => {
1215- Fields :: empty ( )
1216- }
1198+ Str ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive | Opaque | Missing
1199+ | Wildcard => Fields :: empty ( ) ,
12171200 } ;
12181201 debug ! ( "Fields::wildcards({:?}, {:?}) = {:#?}" , constructor, ty, ret) ;
12191202 ret
@@ -1297,9 +1280,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12971280 & FloatRange ( lo, hi, end) => PatKind :: Range ( PatRange { lo, hi, end } ) ,
12981281 IntRange ( range) => return range. to_pat ( pcx. cx . tcx , pcx. ty ) ,
12991282 NonExhaustive => PatKind :: Wild ,
1283+ Wildcard => return Pat :: wildcard_from_ty ( pcx. ty ) ,
13001284 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`"
13031287 ) ,
13041288 } ;
13051289
0 commit comments