Skip to content

Commit 778c7e1

Browse files
committed
Move constructor selection logic to PlaceInfo
1 parent 3602b9d commit 778c7e1

File tree

1 file changed

+79
-56
lines changed

1 file changed

+79
-56
lines changed

Diff for: compiler/rustc_pattern_analysis/src/usefulness.rs

+79-56
Original file line numberDiff line numberDiff line change
@@ -767,9 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
767767
fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
768768
self.cx.ctor_arity(ctor, self.ty)
769769
}
770-
fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
771-
self.cx.ctors_for_ty(self.ty)
772-
}
773770
fn wild_from_ctor(&self, ctor: Constructor<Cx>) -> WitnessPat<Cx> {
774771
WitnessPat::wild_from_ctor(self.cx, ctor, self.ty.clone())
775772
}
@@ -822,7 +819,8 @@ impl fmt::Display for ValidityConstraint {
822819
}
823820
}
824821

825-
/// Data about a place under investigation.
822+
/// Data about a place under investigation. Its methods contain a lot of the logic used to analyze
823+
/// the constructors in the matrix.
826824
struct PlaceInfo<Cx: TypeCx> {
827825
/// The type of the place.
828826
ty: Cx::Ty,
@@ -833,6 +831,8 @@ struct PlaceInfo<Cx: TypeCx> {
833831
}
834832

835833
impl<Cx: TypeCx> PlaceInfo<Cx> {
834+
/// Given a constructor for the current place, we return one `PlaceInfo` for each field of the
835+
/// constructor.
836836
fn specialize<'a>(
837837
&'a self,
838838
cx: &'a Cx,
@@ -846,6 +846,77 @@ impl<Cx: TypeCx> PlaceInfo<Cx> {
846846
is_scrutinee: false,
847847
})
848848
}
849+
850+
/// This analyzes a column of constructors corresponding to the current place. It returns a pair
851+
/// `(split_ctors, missing_ctors)`.
852+
///
853+
/// `split_ctors` is a splitted list of constructors that cover the whole type. This will be
854+
/// used to specialize the matrix.
855+
///
856+
/// `missing_ctors` is a list of the constructors not found in the column, for reporting
857+
/// purposes.
858+
fn split_column_ctors<'a>(
859+
&self,
860+
cx: &Cx,
861+
ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
862+
) -> Result<(SmallVec<[Constructor<Cx>; 1]>, Vec<Constructor<Cx>>), Cx::Error>
863+
where
864+
Cx: 'a,
865+
{
866+
let ctors_for_ty = cx.ctors_for_ty(&self.ty)?;
867+
868+
// We treat match scrutinees of type `!` or `EmptyEnum` differently.
869+
let is_toplevel_exception =
870+
self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
871+
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
872+
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
873+
let empty_arms_are_unreachable = self.validity.is_known_valid()
874+
&& (is_toplevel_exception
875+
|| cx.is_exhaustive_patterns_feature_on()
876+
|| cx.is_min_exhaustive_patterns_feature_on());
877+
// Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
878+
// toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
879+
let can_omit_empty_arms = empty_arms_are_unreachable
880+
|| is_toplevel_exception
881+
|| cx.is_exhaustive_patterns_feature_on();
882+
883+
// Analyze the constructors present in this column.
884+
let mut split_set = ctors_for_ty.split(ctors);
885+
let all_missing = split_set.present.is_empty();
886+
887+
// Build the set of constructors we will specialize with. It must cover the whole type, so
888+
// we add `Missing` to represent the missing ones. This is explained under "Constructor
889+
// Splitting" at the top of this file.
890+
let mut split_ctors = split_set.present;
891+
if !(split_set.missing.is_empty()
892+
&& (split_set.missing_empty.is_empty() || empty_arms_are_unreachable))
893+
{
894+
split_ctors.push(Constructor::Missing);
895+
}
896+
897+
// Which empty constructors are considered missing. We ensure that
898+
// `!missing_ctors.is_empty() => split_ctors.contains(Missing)`. The converse usually holds
899+
// except when `!self.validity.is_known_valid()`.
900+
let mut missing_ctors = split_set.missing;
901+
if !can_omit_empty_arms {
902+
missing_ctors.append(&mut split_set.missing_empty);
903+
}
904+
905+
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top
906+
// level we prefer to list all constructors.
907+
let report_individual_missing_ctors = self.is_scrutinee || !all_missing;
908+
if !missing_ctors.is_empty() && !report_individual_missing_ctors {
909+
// Report `_` as missing.
910+
missing_ctors = vec![Constructor::Wildcard];
911+
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
912+
// We need to report a `_` anyway, so listing other constructors would be redundant.
913+
// `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
914+
// up by diagnostics to add a note about why `_` is required here.
915+
missing_ctors = vec![Constructor::NonExhaustive];
916+
}
917+
918+
Ok((split_ctors, missing_ctors))
919+
}
849920
}
850921

851922
impl<Cx: TypeCx> Clone for PlaceInfo<Cx> {
@@ -1469,61 +1540,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14691540
};
14701541
};
14711542

1472-
let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later.
1473-
let pcx = &PlaceCtxt { cx: mcx.tycx, ty };
1474-
debug!("ty: {:?}", pcx.ty);
1475-
let ctors_for_ty = pcx.ctors_for_ty()?;
1476-
1477-
// We treat match scrutinees of type `!` or `EmptyEnum` differently.
1478-
let is_toplevel_exception =
1479-
place.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
1480-
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
1481-
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1482-
let empty_arms_are_unreachable = place.validity.is_known_valid()
1483-
&& (is_toplevel_exception
1484-
|| mcx.tycx.is_exhaustive_patterns_feature_on()
1485-
|| mcx.tycx.is_min_exhaustive_patterns_feature_on());
1486-
// Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
1487-
// toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
1488-
let can_omit_empty_arms = empty_arms_are_unreachable
1489-
|| is_toplevel_exception
1490-
|| mcx.tycx.is_exhaustive_patterns_feature_on();
1491-
14921543
// Analyze the constructors present in this column.
1544+
debug!("ty: {:?}", place.ty);
14931545
let ctors = matrix.heads().map(|p| p.ctor());
1494-
let mut split_set = ctors_for_ty.split(ctors);
1495-
let all_missing = split_set.present.is_empty();
1496-
// Build the set of constructors we will specialize with. It must cover the whole type.
1497-
// We need to iterate over a full set of constructors, so we add `Missing` to represent the
1498-
// missing ones. This is explained under "Constructor Splitting" at the top of this file.
1499-
let mut split_ctors = split_set.present;
1500-
if !(split_set.missing.is_empty()
1501-
&& (split_set.missing_empty.is_empty() || empty_arms_are_unreachable))
1502-
{
1503-
split_ctors.push(Constructor::Missing);
1504-
}
1505-
1506-
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
1507-
// split_ctors.contains(Missing)`. The converse usually holds except when
1508-
// `!place_validity.is_known_valid()`.
1509-
let mut missing_ctors = split_set.missing;
1510-
if !can_omit_empty_arms {
1511-
missing_ctors.append(&mut split_set.missing_empty);
1512-
}
1513-
1514-
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top
1515-
// level we prefer to list all constructors.
1516-
let report_individual_missing_ctors = place.is_scrutinee || !all_missing;
1517-
if !missing_ctors.is_empty() && !report_individual_missing_ctors {
1518-
// Report `_` as missing.
1519-
missing_ctors = vec![Constructor::Wildcard];
1520-
} else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) {
1521-
// We need to report a `_` anyway, so listing other constructors would be redundant.
1522-
// `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked
1523-
// up by diagnostics to add a note about why `_` is required here.
1524-
missing_ctors = vec![Constructor::NonExhaustive];
1525-
}
1546+
let (split_ctors, missing_ctors) = place.split_column_ctors(mcx.tycx, ctors)?;
15261547

1548+
let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later.
1549+
let pcx = &PlaceCtxt { cx: mcx.tycx, ty };
15271550
let mut ret = WitnessMatrix::empty();
15281551
for ctor in split_ctors {
15291552
// Dig into rows that match `ctor`.

0 commit comments

Comments
 (0)