@@ -238,7 +238,7 @@ use super::{FieldPat, Pat, PatKind, PatRange};
238
238
use rustc:: hir:: def_id:: DefId ;
239
239
use rustc:: hir:: { HirId , RangeEnd } ;
240
240
use rustc:: ty:: layout:: { Integer , IntegerExt , Size , VariantIdx } ;
241
- use rustc:: ty:: { self , Const , Ty , TyCtxt , TypeFoldable } ;
241
+ use rustc:: ty:: { self , Const , Ty , TyCtxt , TypeFoldable , VariantDef } ;
242
242
243
243
use rustc:: lint;
244
244
use rustc:: mir:: interpret:: { truncate, AllocId , ConstValue , Pointer , Scalar } ;
@@ -354,7 +354,7 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> {
354
354
}
355
355
356
356
impl < ' tcx > Pat < ' tcx > {
357
- fn is_wildcard ( & self ) -> bool {
357
+ pub ( super ) fn is_wildcard ( & self ) -> bool {
358
358
match * self . kind {
359
359
PatKind :: Binding { subpattern : None , .. } | PatKind :: Wild => true ,
360
360
_ => false ,
@@ -596,9 +596,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
596
596
}
597
597
}
598
598
599
- fn is_local ( & self , ty : Ty < ' tcx > ) -> bool {
599
+ // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
600
+ pub fn is_foreign_non_exhaustive_enum ( & self , ty : Ty < ' tcx > ) -> bool {
600
601
match ty. kind {
601
- ty:: Adt ( adt_def, ..) => adt_def. did . is_local ( ) ,
602
+ ty:: Adt ( def, ..) => {
603
+ def. is_enum ( ) && def. is_variant_list_non_exhaustive ( ) && !def. did . is_local ( )
604
+ }
605
+ _ => false ,
606
+ }
607
+ }
608
+
609
+ // Returns whether the given variant is from another crate and has its fields declared
610
+ // `#[non_exhaustive]`.
611
+ fn is_foreign_non_exhaustive_variant ( & self , ty : Ty < ' tcx > , variant : & VariantDef ) -> bool {
612
+ match ty. kind {
613
+ ty:: Adt ( def, ..) => variant. is_field_list_non_exhaustive ( ) && !def. did . is_local ( ) ,
602
614
_ => false ,
603
615
}
604
616
}
@@ -758,6 +770,10 @@ impl<'tcx> Constructor<'tcx> {
758
770
// Returns the set of constructors covered by `self` but not by
759
771
// anything in `other_ctors`.
760
772
fn subtract_ctors ( & self , other_ctors : & Vec < Constructor < ' tcx > > ) -> Vec < Constructor < ' tcx > > {
773
+ if other_ctors. is_empty ( ) {
774
+ return vec ! [ self . clone( ) ] ;
775
+ }
776
+
761
777
match self {
762
778
// Those constructors can only match themselves.
763
779
Single | Variant ( _) | ConstantValue ( ..) | FloatRange ( ..) => {
@@ -858,8 +874,7 @@ impl<'tcx> Constructor<'tcx> {
858
874
vec ! [ Pat :: wildcard_from_ty( substs. type_at( 0 ) ) ]
859
875
} else {
860
876
let variant = & adt. variants [ self . variant_index_for_adt ( cx, adt) ] ;
861
- let is_non_exhaustive =
862
- variant. is_field_list_non_exhaustive ( ) && !cx. is_local ( ty) ;
877
+ let is_non_exhaustive = cx. is_foreign_non_exhaustive_variant ( ty, variant) ;
863
878
variant
864
879
. fields
865
880
. iter ( )
@@ -1205,6 +1220,8 @@ impl<'tcx> Witness<'tcx> {
1205
1220
///
1206
1221
/// We make sure to omit constructors that are statically impossible. E.g., for
1207
1222
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
1223
+ /// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
1224
+ /// `cx.is_uninhabited()`).
1208
1225
fn all_constructors < ' a , ' tcx > (
1209
1226
cx : & mut MatchCheckCtxt < ' a , ' tcx > ,
1210
1227
pcx : PatCtxt < ' tcx > ,
@@ -1235,47 +1252,45 @@ fn all_constructors<'a, 'tcx>(
1235
1252
vec ! [ Slice ( Slice { array_len: None , kind } ) ]
1236
1253
}
1237
1254
ty:: Adt ( def, substs) if def. is_enum ( ) => {
1238
- let ctors: Vec < _ > = def
1239
- . variants
1240
- . iter ( )
1241
- . filter ( |v| {
1242
- !cx . tcx . features ( ) . exhaustive_patterns
1243
- || !v
1244
- . uninhabited_from ( cx. tcx , substs, def. adt_kind ( ) )
1255
+ let ctors: Vec < _ > = if cx . tcx . features ( ) . exhaustive_patterns {
1256
+ // If `exhaustive_patterns` is enabled, we exclude variants known to be
1257
+ // uninhabited.
1258
+ def . variants
1259
+ . iter ( )
1260
+ . filter ( |v| {
1261
+ !v . uninhabited_from ( cx. tcx , substs, def. adt_kind ( ) )
1245
1262
. contains ( cx. tcx , cx. module )
1246
- } )
1247
- . map ( |v| Variant ( v. def_id ) )
1248
- . collect ( ) ;
1249
-
1250
- // If our scrutinee is *privately* an empty enum, we must treat it as though it had an
1251
- // "unknown" constructor (in that case, all other patterns obviously can't be variants)
1252
- // to avoid exposing its emptyness. See the `match_privately_empty` test for details.
1253
- // FIXME: currently the only way I know of something can be a privately-empty enum is
1254
- // when the exhaustive_patterns feature flag is not present, so this is only needed for
1255
- // that case.
1256
- let is_privately_empty = ctors. is_empty ( ) && !cx. is_uninhabited ( pcx. ty ) ;
1257
- // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
1258
- // additionnal "unknown" constructor.
1259
- let is_declared_nonexhaustive =
1260
- def. is_variant_list_non_exhaustive ( ) && !cx. is_local ( pcx. ty ) ;
1261
-
1262
- if is_privately_empty || is_declared_nonexhaustive {
1263
- // There is no point in enumerating all possible variants, because the user can't
1264
- // actually match against them themselves. So we return only the fictitious
1265
- // constructor.
1266
- // E.g., in an example like:
1267
- // ```
1268
- // let err: io::ErrorKind = ...;
1269
- // match err {
1270
- // io::ErrorKind::NotFound => {},
1271
- // }
1272
- // ```
1273
- // we don't want to show every possible IO error, but instead have only `_` as the
1274
- // witness.
1275
- vec ! [ NonExhaustive ]
1263
+ } )
1264
+ . map ( |v| Variant ( v. def_id ) )
1265
+ . collect ( )
1276
1266
} else {
1277
- ctors
1278
- }
1267
+ def. variants . iter ( ) . map ( |v| Variant ( v. def_id ) ) . collect ( )
1268
+ } ;
1269
+
1270
+ // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
1271
+ // additional "unknown" constructor.
1272
+ // There is no point in enumerating all possible variants, because the user can't
1273
+ // actually match against them all themselves. So we always return only the fictitious
1274
+ // constructor.
1275
+ // E.g., in an example like:
1276
+ // ```
1277
+ // let err: io::ErrorKind = ...;
1278
+ // match err {
1279
+ // io::ErrorKind::NotFound => {},
1280
+ // }
1281
+ // ```
1282
+ // we don't want to show every possible IO error, but instead have only `_` as the
1283
+ // witness.
1284
+ let is_declared_nonexhaustive = cx. is_foreign_non_exhaustive_enum ( pcx. ty ) ;
1285
+
1286
+ // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
1287
+ // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
1288
+ // an empty match will still be considered exhaustive because that case is handled
1289
+ // separately in `check_match`.
1290
+ let is_secretly_empty =
1291
+ def. variants . is_empty ( ) && !cx. tcx . features ( ) . exhaustive_patterns ;
1292
+
1293
+ if is_secretly_empty || is_declared_nonexhaustive { vec ! [ NonExhaustive ] } else { ctors }
1279
1294
}
1280
1295
ty:: Char => {
1281
1296
vec ! [
@@ -1605,6 +1620,7 @@ pub fn is_useful<'p, 'tcx>(
1605
1620
v : & PatStack < ' p , ' tcx > ,
1606
1621
witness_preference : WitnessPreference ,
1607
1622
hir_id : HirId ,
1623
+ is_top_level : bool ,
1608
1624
) -> Usefulness < ' tcx , ' p > {
1609
1625
let & Matrix ( ref rows) = matrix;
1610
1626
debug ! ( "is_useful({:#?}, {:#?})" , matrix, v) ;
@@ -1632,7 +1648,7 @@ pub fn is_useful<'p, 'tcx>(
1632
1648
let mut unreachable_pats = Vec :: new ( ) ;
1633
1649
let mut any_is_useful = false ;
1634
1650
for v in vs {
1635
- let res = is_useful ( cx, & matrix, & v, witness_preference, hir_id) ;
1651
+ let res = is_useful ( cx, & matrix, & v, witness_preference, hir_id, false ) ;
1636
1652
match res {
1637
1653
Useful ( pats) => {
1638
1654
any_is_useful = true ;
@@ -1732,7 +1748,7 @@ pub fn is_useful<'p, 'tcx>(
1732
1748
} else {
1733
1749
let matrix = matrix. specialize_wildcard ( ) ;
1734
1750
let v = v. to_tail ( ) ;
1735
- let usefulness = is_useful ( cx, & matrix, & v, witness_preference, hir_id) ;
1751
+ let usefulness = is_useful ( cx, & matrix, & v, witness_preference, hir_id, false ) ;
1736
1752
1737
1753
// In this case, there's at least one "free"
1738
1754
// constructor that is only matched against by
@@ -1761,7 +1777,10 @@ pub fn is_useful<'p, 'tcx>(
1761
1777
// `(<direction-1>, <direction-2>, true)` - we are
1762
1778
// satisfied with `(_, _, true)`. In this case,
1763
1779
// `used_ctors` is empty.
1764
- if missing_ctors. all_ctors_are_missing ( ) {
1780
+ // The exception is: if we are at the top-level, for example in an empty match, we
1781
+ // sometimes prefer reporting the list of constructors instead of just `_`.
1782
+ let report_ctors_rather_than_wildcard = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
1783
+ if missing_ctors. all_ctors_are_missing ( ) && !report_ctors_rather_than_wildcard {
1765
1784
// All constructors are unused. Add a wild pattern
1766
1785
// rather than each individual constructor.
1767
1786
usefulness. apply_wildcard ( pcx. ty )
@@ -1793,7 +1812,7 @@ fn is_useful_specialized<'p, 'tcx>(
1793
1812
cx. pattern_arena . alloc_from_iter ( ctor. wildcard_subpatterns ( cx, lty) ) ;
1794
1813
let matrix = matrix. specialize_constructor ( cx, & ctor, ctor_wild_subpatterns) ;
1795
1814
v. specialize_constructor ( cx, & ctor, ctor_wild_subpatterns)
1796
- . map ( |v| is_useful ( cx, & matrix, & v, witness_preference, hir_id) )
1815
+ . map ( |v| is_useful ( cx, & matrix, & v, witness_preference, hir_id, false ) )
1797
1816
. map ( |u| u. apply_constructor ( cx, & ctor, lty) )
1798
1817
. unwrap_or ( NotUseful )
1799
1818
}
@@ -2308,7 +2327,7 @@ fn specialize_one_pattern<'p, 'tcx>(
2308
2327
2309
2328
PatKind :: Variant { adt_def, variant_index, ref subpatterns, .. } => {
2310
2329
let ref variant = adt_def. variants [ variant_index] ;
2311
- let is_non_exhaustive = variant . is_field_list_non_exhaustive ( ) && ! cx. is_local ( pat. ty ) ;
2330
+ let is_non_exhaustive = cx. is_foreign_non_exhaustive_variant ( pat. ty , variant ) ;
2312
2331
Some ( Variant ( variant. def_id ) )
2313
2332
. filter ( |variant_constructor| variant_constructor == constructor)
2314
2333
. map ( |_| {
0 commit comments