@@ -196,6 +196,28 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
196196 }
197197 } ) . clone ( )
198198 }
199+
200+ fn is_uninhabited ( & self , ty : Ty < ' tcx > ) -> bool {
201+ if self . tcx . sess . features . borrow ( ) . never_type {
202+ ty. is_uninhabited_from ( self . module , self . tcx )
203+ } else {
204+ false
205+ }
206+ }
207+
208+ fn is_variant_uninhabited ( & self ,
209+ variant : & ' tcx ty:: VariantDef ,
210+ substs : & ' tcx ty:: subst:: Substs < ' tcx > ) -> bool
211+ {
212+ if self . tcx . sess . features . borrow ( ) . never_type {
213+ let forest = variant. uninhabited_from (
214+ & mut FxHashMap :: default ( ) , self . tcx , substs, AdtKind :: Enum
215+ ) ;
216+ forest. contains ( self . tcx , self . module )
217+ } else {
218+ false
219+ }
220+ }
199221}
200222
201223#[ derive( Clone , Debug , PartialEq ) ]
@@ -379,48 +401,32 @@ impl<'tcx> Witness<'tcx> {
379401fn all_constructors < ' a , ' tcx : ' a > ( cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
380402 pcx : PatternContext < ' tcx > ) -> Vec < Constructor >
381403{
382- let check_inhabited = cx. tcx . sess . features . borrow ( ) . never_type ;
383404 debug ! ( "all_constructors({:?})" , pcx. ty) ;
384405 match pcx. ty . sty {
385406 ty:: TyBool =>
386407 [ true , false ] . iter ( ) . map ( |b| ConstantValue ( ConstVal :: Bool ( * b) ) ) . collect ( ) ,
387408 ty:: TySlice ( ref sub_ty) => {
388- if sub_ty. is_uninhabited_from ( cx. module , cx. tcx )
389- && check_inhabited
390- {
409+ if cx. is_uninhabited ( sub_ty) {
391410 vec ! [ Slice ( 0 ) ]
392411 } else {
393412 ( 0 ..pcx. max_slice_length +1 ) . map ( |length| Slice ( length) ) . collect ( )
394413 }
395414 }
396415 ty:: TyArray ( ref sub_ty, length) => {
397- if length == 0 || !( sub_ty. is_uninhabited_from ( cx. module , cx. tcx )
398- && check_inhabited)
399- {
400- vec ! [ Slice ( length) ]
401- } else {
416+ if length > 0 && cx. is_uninhabited ( sub_ty) {
402417 vec ! [ ]
418+ } else {
419+ vec ! [ Slice ( length) ]
403420 }
404421 }
405422 ty:: TyAdt ( def, substs) if def. is_enum ( ) && def. variants . len ( ) != 1 => {
406- def. variants . iter ( ) . filter_map ( |v| {
407- let mut visited = FxHashMap :: default ( ) ;
408- let forest = v. uninhabited_from ( & mut visited,
409- cx. tcx , substs,
410- AdtKind :: Enum ) ;
411- if forest. contains ( cx. tcx , cx. module )
412- && check_inhabited
413- {
414- None
415- } else {
416- Some ( Variant ( v. did ) )
417- }
418- } ) . collect ( )
423+ def. variants . iter ( )
424+ . filter ( |v| !cx. is_variant_uninhabited ( v, substs) )
425+ . map ( |v| Variant ( v. did ) )
426+ . collect ( )
419427 }
420428 _ => {
421- if pcx. ty . is_uninhabited_from ( cx. module , cx. tcx )
422- && check_inhabited
423- {
429+ if cx. is_uninhabited ( pcx. ty ) {
424430 vec ! [ ]
425431 } else {
426432 vec ! [ Single ]
@@ -564,7 +570,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
564570
565571 assert ! ( rows. iter( ) . all( |r| r. len( ) == v. len( ) ) ) ;
566572
567-
568573 let pcx = PatternContext {
569574 ty : rows. iter ( ) . map ( |r| r[ 0 ] . ty ) . find ( |ty| !ty. references_error ( ) )
570575 . unwrap_or ( v[ 0 ] . ty ) ,
@@ -590,7 +595,6 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
590595 let missing_ctors: Vec < Constructor > = all_ctors. iter ( ) . filter ( |c| {
591596 !used_ctors. contains ( * c)
592597 } ) . cloned ( ) . collect ( ) ;
593- debug ! ( "missing_ctors = {:?}" , missing_ctors) ;
594598
595599 // `missing_ctors` is the set of constructors from the same type as the
596600 // first column of `matrix` that are matched only by wildcard patterns
@@ -599,8 +603,23 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
599603 // Therefore, if there is some pattern that is unmatched by `matrix`,
600604 // it will still be unmatched if the first constructor is replaced by
601605 // any of the constructors in `missing_ctors`
602-
603- if missing_ctors. is_empty ( ) {
606+ //
607+ // However, if our scrutinee is *privately* an empty enum, we
608+ // must treat it as though it had an "unknown" constructor (in
609+ // that case, all other patterns obviously can't be variants)
610+ // to avoid exposing its emptyness. See the `match_privately_empty`
611+ // test for details.
612+ //
613+ // FIXME: currently the only way I know of something can
614+ // be a privately-empty enum is when the never_type
615+ // feature flag is not present, so this is only
616+ // needed for that case.
617+
618+ let is_privately_empty =
619+ all_ctors. is_empty ( ) && !cx. is_uninhabited ( pcx. ty ) ;
620+ debug ! ( "missing_ctors={:?} is_privately_empty={:?}" , missing_ctors,
621+ is_privately_empty) ;
622+ if missing_ctors. is_empty ( ) && !is_privately_empty {
604623 all_ctors. into_iter ( ) . map ( |c| {
605624 is_useful_specialized ( cx, matrix, v, c. clone ( ) , pcx. ty , witness)
606625 } ) . find ( |result| result. is_useful ( ) ) . unwrap_or ( NotUseful )
@@ -649,6 +668,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
649668 lty : Ty < ' tcx > ,
650669 witness : WitnessPreference ) -> Usefulness < ' tcx >
651670{
671+ debug ! ( "is_useful_specialized({:?}, {:?}, {:?})" , v, ctor, lty) ;
652672 let sub_pat_tys = constructor_sub_pattern_tys ( cx, & ctor, lty) ;
653673 let wild_patterns_owned: Vec < _ > = sub_pat_tys. iter ( ) . map ( |ty| {
654674 Pattern {
@@ -754,7 +774,19 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
754774 ty:: TyRef ( _, ref ty_and_mut) => vec ! [ ty_and_mut. ty] ,
755775 ty:: TyAdt ( adt, substs) => {
756776 adt. variants [ ctor. variant_index_for_adt ( adt) ] . fields . iter ( ) . map ( |field| {
757- field. ty ( cx. tcx , substs)
777+ let is_visible = adt. is_enum ( )
778+ || field. vis . is_accessible_from ( cx. module , cx. tcx ) ;
779+ if is_visible {
780+ field. ty ( cx. tcx , substs)
781+ } else {
782+ // Treat all non-visible fields as nil. They
783+ // can't appear in any other pattern from
784+ // this match (because they are private),
785+ // so their type does not matter - but
786+ // we don't want to know they are
787+ // uninhabited.
788+ cx. tcx . mk_nil ( )
789+ }
758790 } ) . collect ( )
759791 }
760792 _ => vec ! [ ] ,
0 commit comments