@@ -737,15 +737,13 @@ pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
737
737
pub ( crate ) mcx : MatchCtxt < ' a , Cx > ,
738
738
/// Type of the place under investigation.
739
739
pub ( crate ) ty : Cx :: Ty ,
740
- /// Whether the place is the original scrutinee place, as opposed to a subplace of it.
741
- pub ( crate ) is_scrutinee : bool ,
742
740
}
743
741
744
742
impl < ' a , Cx : TypeCx > PlaceCtxt < ' a , Cx > {
745
743
/// A `PlaceCtxt` when code other than `is_useful` needs one.
746
744
#[ cfg_attr( not( feature = "rustc" ) , allow( dead_code) ) ]
747
745
pub ( crate ) fn new_dummy ( mcx : MatchCtxt < ' a , Cx > , ty : Cx :: Ty ) -> Self {
748
- PlaceCtxt { mcx, ty, is_scrutinee : false }
746
+ PlaceCtxt { mcx, ty }
749
747
}
750
748
751
749
pub ( crate ) fn ctor_arity ( & self , ctor : & Constructor < Cx > ) -> usize {
@@ -768,30 +766,16 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
768
766
pub enum ValidityConstraint {
769
767
ValidOnly ,
770
768
MaybeInvalid ,
771
- /// Option for backwards compatibility: the place is not known to be valid but we allow omitting
772
- /// `useful && !reachable` arms anyway.
773
- MaybeInvalidButAllowOmittingArms ,
774
769
}
775
770
776
771
impl ValidityConstraint {
777
772
pub fn from_bool ( is_valid_only : bool ) -> Self {
778
773
if is_valid_only { ValidOnly } else { MaybeInvalid }
779
774
}
780
775
781
- fn allow_omitting_side_effecting_arms ( self ) -> Self {
782
- match self {
783
- MaybeInvalid | MaybeInvalidButAllowOmittingArms => MaybeInvalidButAllowOmittingArms ,
784
- // There are no side-effecting empty arms here, nothing to do.
785
- ValidOnly => ValidOnly ,
786
- }
787
- }
788
-
789
776
fn is_known_valid ( self ) -> bool {
790
777
matches ! ( self , ValidOnly )
791
778
}
792
- fn allows_omitting_empty_arms ( self ) -> bool {
793
- matches ! ( self , ValidOnly | MaybeInvalidButAllowOmittingArms )
794
- }
795
779
796
780
/// If the place has validity given by `self` and we read that the value at the place has
797
781
/// constructor `ctor`, this computes what we can assume about the validity of the constructor
@@ -814,7 +798,7 @@ impl fmt::Display for ValidityConstraint {
814
798
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
815
799
let s = match self {
816
800
ValidOnly => "✓" ,
817
- MaybeInvalid | MaybeInvalidButAllowOmittingArms => "?" ,
801
+ MaybeInvalid => "?" ,
818
802
} ;
819
803
write ! ( f, "{s}" )
820
804
}
@@ -1456,41 +1440,44 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1456
1440
} ;
1457
1441
1458
1442
debug ! ( "ty: {ty:?}" ) ;
1459
- let pcx = & PlaceCtxt { mcx, ty, is_scrutinee : is_top_level } ;
1443
+ let pcx = & PlaceCtxt { mcx, ty } ;
1444
+ let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1460
1445
1461
1446
// Whether the place/column we are inspecting is known to contain valid data.
1462
1447
let place_validity = matrix. place_validity [ 0 ] ;
1463
- // For backwards compability we allow omitting some empty arms that we ideally shouldn't.
1464
- let place_validity = place_validity. allow_omitting_side_effecting_arms ( ) ;
1448
+ // We treat match scrutinees of type `!` or `EmptyEnum` differently.
1449
+ let is_toplevel_exception =
1450
+ is_top_level && matches ! ( ctors_for_ty, ConstructorSet :: NoConstructors ) ;
1451
+ // Whether empty patterns can be omitted for exhaustiveness.
1452
+ let can_omit_empty_arms = is_toplevel_exception || mcx. tycx . is_exhaustive_patterns_feature_on ( ) ;
1453
+ // Whether empty patterns are counted as useful or not.
1454
+ let empty_arms_are_unreachable = place_validity. is_known_valid ( ) && can_omit_empty_arms;
1465
1455
1466
1456
// Analyze the constructors present in this column.
1467
1457
let ctors = matrix. heads ( ) . map ( |p| p. ctor ( ) ) ;
1468
- let ctors_for_ty = pcx. ctors_for_ty ( ) ?;
1469
- let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ; // For diagnostics.
1470
- let split_set = ctors_for_ty. split ( pcx, ctors) ;
1458
+ let mut split_set = ctors_for_ty. split ( ctors) ;
1471
1459
let all_missing = split_set. present . is_empty ( ) ;
1472
-
1473
1460
// Build the set of constructors we will specialize with. It must cover the whole type.
1461
+ // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1462
+ // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1474
1463
let mut split_ctors = split_set. present ;
1475
- if !split_set. missing . is_empty ( ) {
1476
- // We need to iterate over a full set of constructors, so we add `Missing` to represent the
1477
- // missing ones. This is explained under "Constructor Splitting" at the top of this file.
1478
- split_ctors. push ( Constructor :: Missing ) ;
1479
- } else if !split_set. missing_empty . is_empty ( ) && !place_validity. is_known_valid ( ) {
1480
- // The missing empty constructors are reachable if the place can contain invalid data.
1464
+ if !( split_set. missing . is_empty ( )
1465
+ && ( split_set. missing_empty . is_empty ( ) || empty_arms_are_unreachable) )
1466
+ {
1481
1467
split_ctors. push ( Constructor :: Missing ) ;
1482
1468
}
1483
1469
1484
1470
// Decide what constructors to report.
1471
+ let is_integers = matches ! ( ctors_for_ty, ConstructorSet :: Integers { .. } ) ;
1485
1472
let always_report_all = is_top_level && !is_integers;
1486
1473
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
1487
1474
let report_individual_missing_ctors = always_report_all || !all_missing;
1488
1475
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1489
- // split_ctors.contains(Missing)`. The converse usually holds except in the
1490
- // `MaybeInvalidButAllowOmittingArms` backwards-compatibility case .
1476
+ // split_ctors.contains(Missing)`. The converse usually holds except when
1477
+ // `!place_validity.is_known_valid()` .
1491
1478
let mut missing_ctors = split_set. missing ;
1492
- if !place_validity . allows_omitting_empty_arms ( ) {
1493
- missing_ctors. extend ( split_set. missing_empty ) ;
1479
+ if !can_omit_empty_arms {
1480
+ missing_ctors. append ( & mut split_set. missing_empty ) ;
1494
1481
}
1495
1482
1496
1483
let mut ret = WitnessMatrix :: empty ( ) ;
0 commit comments