@@ -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