@@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd};
242
242
use rustc_middle:: mir:: interpret:: { truncate, AllocId , ConstValue , Pointer , Scalar } ;
243
243
use rustc_middle:: mir:: Field ;
244
244
use rustc_middle:: ty:: layout:: IntegerExt ;
245
- use rustc_middle:: ty:: { self , Const , Ty , TyCtxt , TypeFoldable , VariantDef } ;
245
+ use rustc_middle:: ty:: { self , Const , Ty , TyCtxt , TypeFoldable } ;
246
246
use rustc_session:: lint;
247
247
use rustc_span:: { Span , DUMMY_SP } ;
248
248
use rustc_target:: abi:: { Integer , Size , VariantIdx } ;
@@ -591,7 +591,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
591
591
}
592
592
}
593
593
594
- // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
594
+ /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
595
595
crate fn is_foreign_non_exhaustive_enum ( & self , ty : Ty < ' tcx > ) -> bool {
596
596
match ty. kind {
597
597
ty:: Adt ( def, ..) => {
@@ -600,15 +600,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
600
600
_ => false ,
601
601
}
602
602
}
603
-
604
- // Returns whether the given variant is from another crate and has its fields declared
605
- // `#[non_exhaustive]`.
606
- fn is_foreign_non_exhaustive_variant ( & self , ty : Ty < ' tcx > , variant : & VariantDef ) -> bool {
607
- match ty. kind {
608
- ty:: Adt ( def, ..) => variant. is_field_list_non_exhaustive ( ) && !def. did . is_local ( ) ,
609
- _ => false ,
610
- }
611
- }
612
603
}
613
604
614
605
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
@@ -876,7 +867,7 @@ impl<'tcx> Constructor<'tcx> {
876
867
ty : Ty < ' tcx > ,
877
868
fields : Fields < ' p , ' tcx > ,
878
869
) -> Pat < ' tcx > {
879
- let mut subpatterns = fields. into_iter ( ) . cloned ( ) ;
870
+ let mut subpatterns = fields. all_patterns ( ) ;
880
871
881
872
let pat = match self {
882
873
Single | Variant ( _) => match ty. kind {
@@ -945,12 +936,45 @@ impl<'tcx> Constructor<'tcx> {
945
936
}
946
937
}
947
938
939
+ #[ derive( Debug , Copy , Clone ) ]
940
+ enum FilteredField < ' p , ' tcx > {
941
+ Kept ( & ' p Pat < ' tcx > ) ,
942
+ Hidden ( Ty < ' tcx > ) ,
943
+ }
944
+
945
+ impl < ' p , ' tcx > FilteredField < ' p , ' tcx > {
946
+ fn kept ( self ) -> Option < & ' p Pat < ' tcx > > {
947
+ match self {
948
+ FilteredField :: Kept ( p) => Some ( p) ,
949
+ FilteredField :: Hidden ( _) => None ,
950
+ }
951
+ }
952
+
953
+ fn to_pattern ( self ) -> Pat < ' tcx > {
954
+ match self {
955
+ FilteredField :: Kept ( p) => p. clone ( ) ,
956
+ FilteredField :: Hidden ( ty) => Pat :: wildcard_from_ty ( ty) ,
957
+ }
958
+ }
959
+ }
960
+
948
961
/// A value can be decomposed into a constructor applied to some fields. This struct represents
949
962
/// those fields, generalized to allow patterns in each field. See also `Constructor`.
963
+ ///
964
+ /// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
965
+ /// uninhabited. For that, we filter these fields out of the matrix. This is subtle because we
966
+ /// still need to have those fields back when going to/from a `Pat`. Mot of this is handled
967
+ /// automatically in `Fields`, but when constructing or deconstructing fields you need to use the
968
+ /// correct method. As a rule, when going to/from the matrix, use the filtered field list; when
969
+ /// going to/from `Pat`, use the full field list.
970
+ /// This filtering is uncommon in practice, because uninhabited fields are rarely used.
950
971
#[ derive( Debug , Clone ) ]
951
972
enum Fields < ' p , ' tcx > {
973
+ /// Lists of patterns that don't contain any filtered fields.
952
974
Slice ( & ' p [ Pat < ' tcx > ] ) ,
953
975
Vec ( SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) ,
976
+ /// Patterns where some of the fields need to be hidden.
977
+ Filtered ( SmallVec < [ FilteredField < ' p , ' tcx > ; 2 ] > ) ,
954
978
}
955
979
956
980
impl < ' p , ' tcx > Fields < ' p , ' tcx > {
@@ -964,7 +988,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
964
988
Fields :: Slice ( std:: slice:: from_ref ( pat) )
965
989
}
966
990
967
- fn from_vec ( pats : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) -> Self {
991
+ /// Construct a new `Fields` from the given patterns. You must be sure those patterns can't
992
+ /// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`.
993
+ fn from_vec_unfiltered ( pats : SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) -> Self {
968
994
Fields :: Vec ( pats)
969
995
}
970
996
@@ -999,26 +1025,40 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
999
1025
Fields :: from_single_pattern ( wildcard_from_ty ( substs. type_at ( 0 ) ) )
1000
1026
} else {
1001
1027
let variant = & adt. variants [ constructor. variant_index_for_adt ( cx, adt) ] ;
1002
- let is_non_exhaustive = cx. is_foreign_non_exhaustive_variant ( ty, variant) ;
1003
- Fields :: wildcards_from_tys (
1004
- cx,
1005
- variant. fields . iter ( ) . map ( |field| {
1006
- let ty = field. ty ( cx. tcx , substs) ;
1007
- let is_visible = adt. is_enum ( )
1008
- || field. vis . is_accessible_from ( cx. module , cx. tcx ) ;
1009
- let is_inhabited = !cx. is_uninhabited ( ty) ;
1010
- // Treat all uninhabited non-visible fields as `TyErr`. They can't
1011
- // appear in any other pattern from this match (because they are
1012
- // private), so their type does not matter - but we don't want
1013
- // to know they are uninhabited.
1014
- // Also treat all uninhabited types in non-exhaustive variants as
1015
- // `TyErr`.
1016
- let allowed_to_inspect =
1017
- is_inhabited || ( is_visible && !is_non_exhaustive) ;
1018
-
1019
- if allowed_to_inspect { ty } else { cx. tcx . types . err }
1020
- } ) ,
1021
- )
1028
+ // Whether we must not match the fields of this variant exhaustively.
1029
+ let is_non_exhaustive =
1030
+ variant. is_field_list_non_exhaustive ( ) && !adt. did . is_local ( ) ;
1031
+ let field_tys = variant. fields . iter ( ) . map ( |field| field. ty ( cx. tcx , substs) ) ;
1032
+ // In the following cases, we don't need to filter out any fields. This is
1033
+ // the vast majority of real cases, since uninhabited fields are uncommon.
1034
+ let has_no_hidden_fields = ( adt. is_enum ( ) && !is_non_exhaustive)
1035
+ || !field_tys. clone ( ) . any ( |ty| cx. is_uninhabited ( ty) ) ;
1036
+
1037
+ if has_no_hidden_fields {
1038
+ Fields :: wildcards_from_tys ( cx, field_tys)
1039
+ } else {
1040
+ let fields = variant
1041
+ . fields
1042
+ . iter ( )
1043
+ . map ( |field| {
1044
+ let ty = field. ty ( cx. tcx , substs) ;
1045
+ let is_visible = adt. is_enum ( )
1046
+ || field. vis . is_accessible_from ( cx. module , cx. tcx ) ;
1047
+ let is_uninhabited = cx. is_uninhabited ( ty) ;
1048
+
1049
+ // In the cases of either a `#[non_exhaustive]` field list
1050
+ // or a non-public field, we hide uninhabited fields in
1051
+ // order not to reveal the uninhabitedness of the whole
1052
+ // variant.
1053
+ if is_uninhabited && ( !is_visible || is_non_exhaustive) {
1054
+ FilteredField :: Hidden ( ty)
1055
+ } else {
1056
+ FilteredField :: Kept ( wildcard_from_ty ( ty) )
1057
+ }
1058
+ } )
1059
+ . collect ( ) ;
1060
+ Fields :: Filtered ( fields)
1061
+ }
1022
1062
}
1023
1063
}
1024
1064
_ => Fields :: empty ( ) ,
@@ -1038,29 +1078,30 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1038
1078
match self {
1039
1079
Fields :: Slice ( pats) => pats. len ( ) ,
1040
1080
Fields :: Vec ( pats) => pats. len ( ) ,
1081
+ Fields :: Filtered ( fields) => fields. iter ( ) . filter ( |p| p. kept ( ) . is_some ( ) ) . count ( ) ,
1041
1082
}
1042
1083
}
1043
1084
1044
- fn into_iter ( self ) -> impl Iterator < Item = & ' p Pat < ' tcx > > {
1045
- let pats: SmallVec < _ > = match self {
1046
- Fields :: Slice ( pats) => pats. iter ( ) . collect ( ) ,
1047
- Fields :: Vec ( pats) => pats,
1085
+ /// Returns the complete list of patterns, including hidden fields.
1086
+ fn all_patterns ( self ) -> impl Iterator < Item = Pat < ' tcx > > {
1087
+ let pats: SmallVec < [ _ ; 2 ] > = match self {
1088
+ Fields :: Slice ( pats) => pats. iter ( ) . cloned ( ) . collect ( ) ,
1089
+ Fields :: Vec ( pats) => pats. into_iter ( ) . cloned ( ) . collect ( ) ,
1090
+ Fields :: Filtered ( fields) => {
1091
+ // We don't skip any fields here.
1092
+ fields. into_iter ( ) . map ( |p| p. to_pattern ( ) ) . collect ( )
1093
+ }
1048
1094
} ;
1049
1095
pats. into_iter ( )
1050
1096
}
1051
1097
1052
1098
/// Overrides some of the fields with the provided patterns.
1053
1099
fn replace_with_fieldpats (
1054
1100
& self ,
1055
- cx : & MatchCheckCtxt < ' p , ' tcx > ,
1056
1101
new_pats : impl IntoIterator < Item = & ' p FieldPat < ' tcx > > ,
1057
- is_non_exhaustive : bool ,
1058
1102
) -> Self {
1059
1103
self . replace_fields_indexed (
1060
- new_pats
1061
- . into_iter ( )
1062
- . map ( |pat| ( pat. field . index ( ) , & pat. pattern ) )
1063
- . filter ( |( _, pat) | !( is_non_exhaustive && cx. is_uninhabited ( pat. ty ) ) ) ,
1104
+ new_pats. into_iter ( ) . map ( |pat| ( pat. field . index ( ) , & pat. pattern ) ) ,
1064
1105
)
1065
1106
}
1066
1107
@@ -1080,6 +1121,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1080
1121
pats[ i] = pat
1081
1122
}
1082
1123
}
1124
+ Fields :: Filtered ( fields) => {
1125
+ for ( i, pat) in new_pats {
1126
+ if let FilteredField :: Kept ( p) = & mut fields[ i] {
1127
+ * p = pat
1128
+ }
1129
+ }
1130
+ }
1083
1131
Fields :: Slice ( _) => unreachable ! ( ) ,
1084
1132
}
1085
1133
fields
@@ -1093,7 +1141,21 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1093
1141
pats : impl IntoIterator < Item = Pat < ' tcx > > ,
1094
1142
) -> Self {
1095
1143
let pats: & [ _ ] = cx. pattern_arena . alloc_from_iter ( pats) ;
1096
- Fields :: Slice ( pats)
1144
+
1145
+ match self {
1146
+ Fields :: Filtered ( fields) => {
1147
+ let mut pats = pats. iter ( ) ;
1148
+ let mut fields = fields. clone ( ) ;
1149
+ for f in & mut fields {
1150
+ if let FilteredField :: Kept ( p) = f {
1151
+ // We take one input pattern for each `Kept` field, in order.
1152
+ * p = pats. next ( ) . unwrap ( ) ;
1153
+ }
1154
+ }
1155
+ Fields :: Filtered ( fields)
1156
+ }
1157
+ _ => Fields :: Slice ( pats) ,
1158
+ }
1097
1159
}
1098
1160
1099
1161
fn push_on_patstack ( self , stack : & [ & ' p Pat < ' tcx > ] ) -> PatStack < ' p , ' tcx > {
@@ -1103,6 +1165,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1103
1165
pats. extend_from_slice ( stack) ;
1104
1166
pats
1105
1167
}
1168
+ Fields :: Filtered ( fields) => {
1169
+ // We skip hidden fields here
1170
+ fields. into_iter ( ) . filter_map ( |p| p. kept ( ) ) . chain ( stack. iter ( ) . copied ( ) ) . collect ( )
1171
+ }
1106
1172
} ;
1107
1173
PatStack :: from_vec ( pats)
1108
1174
}
@@ -2411,12 +2477,11 @@ fn specialize_one_pattern<'p, 'tcx>(
2411
2477
if constructor != & Variant ( variant. def_id ) {
2412
2478
return None ;
2413
2479
}
2414
- let is_non_exhaustive = cx. is_foreign_non_exhaustive_variant ( pat. ty , variant) ;
2415
- Some ( ctor_wild_subpatterns. replace_with_fieldpats ( cx, subpatterns, is_non_exhaustive) )
2480
+ Some ( ctor_wild_subpatterns. replace_with_fieldpats ( subpatterns) )
2416
2481
}
2417
2482
2418
2483
PatKind :: Leaf { ref subpatterns } => {
2419
- Some ( ctor_wild_subpatterns. replace_with_fieldpats ( cx , subpatterns, false ) )
2484
+ Some ( ctor_wild_subpatterns. replace_with_fieldpats ( subpatterns) )
2420
2485
}
2421
2486
2422
2487
PatKind :: Deref { ref subpattern } => Some ( Fields :: from_single_pattern ( subpattern) ) ,
@@ -2485,7 +2550,7 @@ fn specialize_one_pattern<'p, 'tcx>(
2485
2550
Some ( & * cx. pattern_arena . alloc ( pattern) )
2486
2551
} )
2487
2552
. collect :: < Option < _ > > ( ) ?;
2488
- Some ( Fields :: from_vec ( pats) )
2553
+ Some ( Fields :: from_vec_unfiltered ( pats) )
2489
2554
}
2490
2555
2491
2556
PatKind :: Constant { .. } | PatKind :: Range { .. } => {
0 commit comments