@@ -1432,39 +1432,38 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1432
1432
1433
1433
debug ! ( "ty: {ty:?}" ) ;
1434
1434
let pcx = & PlaceCtxt { mcx, ty } ;
1435
+ let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1435
1436
1436
1437
// Whether the place/column we are inspecting is known to contain valid data.
1437
1438
let place_validity = matrix. place_validity [ 0 ] ;
1439
+ // We treat match scrutinees of type `!` or `EmptyEnum` differently.
1440
+ let is_toplevel_exception =
1441
+ is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1442
+ // Whether empty patterns can be omitted for exhaustiveness.
1443
+ let can_omit_empty_arms = is_toplevel_exception || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1438
1444
1439
1445
// Analyze the constructors present in this column.
1440
1446
let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1441
- let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1442
- let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ; // For diagnostics.
1443
1447
let mut split_set = ctors_for_ty. split ( ctors) ;
1444
- // We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
1445
- // In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
1446
- // types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
1447
- if !pcx. mcx . tycx . is_exhaustive_patterns_feature_on ( )
1448
- && !( is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) )
1449
- {
1448
+ if !can_omit_empty_arms {
1450
1449
// Treat all missing constructors as nonempty.
1451
1450
// This clears `missing_empty`.
1452
1451
split_set. missing . append ( & mut split_set. missing_empty ) ;
1453
1452
}
1454
1453
let all_missing = split_set. present . is_empty ( ) ;
1455
1454
1456
1455
// Build the set of constructors we will specialize with. It must cover the whole type.
1456
+ // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1457
+ // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1457
1458
let mut split_ctors = split_set. present ;
1458
- if !split_set. missing . is_empty ( ) {
1459
- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1460
- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1461
- split_ctors. push ( Constructor :: Missing ) ;
1462
- } else if !split_set. missing_empty . is_empty ( ) && !place_validity. is_known_valid ( ) {
1463
- // The missing empty constructors are reachable if the place can contain invalid data.
1459
+ if !( split_set. missing . is_empty ( )
1460
+ && ( split_set. missing_empty . is_empty ( ) || place_validity. is_known_valid ( ) ) )
1461
+ {
1464
1462
split_ctors. push ( Constructor :: Missing ) ;
1465
1463
}
1466
1464
1467
1465
// Decide what constructors to report.
1466
+ let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
1468
1467
let always_report_all = is_top_level && !is_integers;
1469
1468
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1470
1469
let report_individual_missing_ctors = always_report_all || !all_missing;
0 commit comments