@@ -208,6 +208,20 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
208208 }
209209 }
210210
211+ fn is_non_exhaustive_enum ( & self , ty : Ty < ' tcx > ) -> bool {
212+ match ty. sty {
213+ ty:: TyAdt ( adt_def, ..) => adt_def. is_enum ( ) && adt_def. is_non_exhaustive ( ) ,
214+ _ => false ,
215+ }
216+ }
217+
218+ fn is_local ( & self , ty : Ty < ' tcx > ) -> bool {
219+ match ty. sty {
220+ ty:: TyAdt ( adt_def, ..) => adt_def. did . is_local ( ) ,
221+ _ => false ,
222+ }
223+ }
224+
211225 fn is_variant_uninhabited ( & self ,
212226 variant : & ' tcx ty:: VariantDef ,
213227 substs : & ' tcx ty:: subst:: Substs < ' tcx > )
@@ -628,9 +642,16 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
628642
629643 let is_privately_empty =
630644 all_ctors. is_empty ( ) && !cx. is_uninhabited ( pcx. ty ) ;
631- debug ! ( "missing_ctors={:?} is_privately_empty={:?}" , missing_ctors,
632- is_privately_empty) ;
633- if missing_ctors. is_empty ( ) && !is_privately_empty {
645+ let is_declared_nonexhaustive =
646+ cx. is_non_exhaustive_enum ( pcx. ty ) && !cx. is_local ( pcx. ty ) ;
647+ debug ! ( "missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}" ,
648+ missing_ctors, is_privately_empty, is_declared_nonexhaustive) ;
649+
650+ // For privately empty and non-exhaustive enums, we work as if there were an "extra"
651+ // `_` constructor for the type, so we can never match over all constructors.
652+ let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
653+
654+ if missing_ctors. is_empty ( ) && !is_non_exhaustive {
634655 all_ctors. into_iter ( ) . map ( |c| {
635656 is_useful_specialized ( cx, matrix, v, c. clone ( ) , pcx. ty , witness)
636657 } ) . find ( |result| result. is_useful ( ) ) . unwrap_or ( NotUseful )
@@ -645,7 +666,51 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
645666 match is_useful ( cx, & matrix, & v[ 1 ..] , witness) {
646667 UsefulWithWitness ( pats) => {
647668 let cx = & * cx;
648- let new_witnesses = if used_ctors. is_empty ( ) {
669+ // In this case, there's at least one "free"
670+ // constructor that is only matched against by
671+ // wildcard patterns.
672+ //
673+ // There are 2 ways we can report a witness here.
674+ // Commonly, we can report all the "free"
675+ // constructors as witnesses, e.g. if we have:
676+ //
677+ // ```
678+ // enum Direction { N, S, E, W }
679+ // let Direction::N = ...;
680+ // ```
681+ //
682+ // we can report 3 witnesses: `S`, `E`, and `W`.
683+ //
684+ // However, there are 2 cases where we don't want
685+ // to do this and instead report a single `_` witness:
686+ //
687+ // 1) If the user is matching against a non-exhaustive
688+ // enum, there is no point in enumerating all possible
689+ // variants, because the user can't actually match
690+ // against them himself, e.g. in an example like:
691+ // ```
692+ // let err: io::ErrorKind = ...;
693+ // match err {
694+ // io::ErrorKind::NotFound => {},
695+ // }
696+ // ```
697+ // we don't want to show every possible IO error,
698+ // but instead have `_` as the witness (this is
699+ // actually *required* if the user specified *all*
700+ // IO errors, but is probably what we want in every
701+ // case).
702+ //
703+ // 2) If the user didn't actually specify a constructor
704+ // in this arm, e.g. in
705+ // ```
706+ // let x: (Direction, Direction, bool) = ...;
707+ // let (_, _, false) = x;
708+ // ```
709+ // we don't want to show all 16 possible witnesses
710+ // `(<direction-1>, <direction-2>, true)` - we are
711+ // satisfied with `(_, _, true)`. In this case,
712+ // `used_ctors` is empty.
713+ let new_witnesses = if is_non_exhaustive || used_ctors. is_empty ( ) {
649714 // All constructors are unused. Add wild patterns
650715 // rather than each individual constructor
651716 pats. into_iter ( ) . map ( |mut witness| {
0 commit comments