@@ -208,6 +208,20 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
208
208
}
209
209
}
210
210
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
+
211
225
fn is_variant_uninhabited ( & self ,
212
226
variant : & ' tcx ty:: VariantDef ,
213
227
substs : & ' tcx ty:: subst:: Substs < ' tcx > )
@@ -628,9 +642,16 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
628
642
629
643
let is_privately_empty =
630
644
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 {
634
655
all_ctors. into_iter ( ) . map ( |c| {
635
656
is_useful_specialized ( cx, matrix, v, c. clone ( ) , pcx. ty , witness)
636
657
} ) . 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>,
645
666
match is_useful ( cx, & matrix, & v[ 1 ..] , witness) {
646
667
UsefulWithWitness ( pats) => {
647
668
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 ( ) {
649
714
// All constructors are unused. Add wild patterns
650
715
// rather than each individual constructor
651
716
pats. into_iter ( ) . map ( |mut witness| {
0 commit comments