@@ -1375,39 +1375,41 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1375
1375
1376
1376
debug ! ( "ty: {ty:?}" ) ;
1377
1377
let pcx = & PlaceCtxt { mcx, ty, is_scrutinee : is_top_level } ;
1378
-
1378
+ let ctors_for_ty = pcx . ctors_for_ty ( ) ;
1379
1379
// Whether the place/column we are inspecting is known to contain valid data.
1380
1380
let place_validity = matrix. place_validity [ 0 ] ;
1381
- // For backwards compability we allow omitting some empty arms that we ideally shouldn't.
1382
- let place_validity = place_validity. allow_omitting_side_effecting_arms ( ) ;
1381
+
1382
+ // For backwards-compatibility we treat match scrutinees of type `!` or `EmptyEnum` differently.
1383
+ let is_toplevel_exception =
1384
+ is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1385
+ // Whether empty patterns are counted as useful or not.
1386
+ let empty_arms_are_unreachable = place_validity. is_known_valid ( )
1387
+ && ( is_toplevel_exception || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ) ;
1388
+ // Whether empty patterns can be omitted for exhaustiveness.
1389
+ let can_omit_empty_arms = is_toplevel_exception || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1383
1390
1384
1391
// Analyze the constructors present in this column.
1385
1392
let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1386
- let ctors_for_ty = pcx. ctors_for_ty ( ) ;
1387
- let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ; // For diagnostics.
1388
1393
let split_set = ctors_for_ty. split ( pcx, ctors) ;
1389
1394
let all_missing = split_set. present . is_empty ( ) ;
1390
-
1391
1395
// Build the set of constructors we will specialize with. It must cover the whole type.
1392
1396
let mut split_ctors = split_set. present ;
1393
- if !split_set. missing . is_empty ( ) {
1394
- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1395
- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1396
- split_ctors. push ( Constructor :: Missing ) ;
1397
- } else if !split_set. missing_empty . is_empty ( ) && !place_validity. is_known_valid ( ) {
1398
- // The missing empty constructors are reachable if the place can contain invalid data.
1397
+ if !split_set. missing . is_empty ( )
1398
+ || ( !split_set. missing_empty . is_empty ( ) && !empty_arms_are_unreachable)
1399
+ {
1399
1400
split_ctors. push ( Constructor :: Missing ) ;
1400
1401
}
1401
1402
1402
1403
// Decide what constructors to report.
1404
+ let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
1403
1405
let always_report_all = is_top_level && !is_integers;
1404
1406
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1405
1407
let report_individual_missing_ctors = always_report_all || !all_missing;
1406
1408
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1407
1409
// split_ctors.contains(Missing)`. The converse usually holds except in the
1408
1410
// `MaybeInvalidButAllowOmittingArms` backwards-compatibility case.
1409
1411
let mut missing_ctors = split_set. missing ;
1410
- if !place_validity . allows_omitting_empty_arms ( ) {
1412
+ if !can_omit_empty_arms {
1411
1413
missing_ctors. extend ( split_set. missing_empty ) ;
1412
1414
}
1413
1415
0 commit comments