Skip to content

Commit 00794ce

Browse files
authored
Rollup merge of #120633 - Nadrieril:place_info, r=compiler-errors
pattern_analysis: gather up place-relevant info We track 3 things about each place during exhaustiveness: its type, its (data) validity, and whether it's the scrutinee place. This PR gathers all three into a single struct. r? ``@compiler-errors``
2 parents faad0e1 + 6cac1c4 commit 00794ce

File tree

1 file changed

+57
-40
lines changed

1 file changed

+57
-40
lines changed

compiler/rustc_pattern_analysis/src/usefulness.rs

+57-40
Original file line numberDiff line numberDiff line change
@@ -767,12 +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 ctor_sub_tys(
771-
&'a self,
772-
ctor: &'a Constructor<Cx>,
773-
) -> impl Iterator<Item = Cx::Ty> + ExactSizeIterator + Captures<'a> {
774-
self.cx.ctor_sub_tys(ctor, self.ty)
775-
}
776770
fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
777771
self.cx.ctors_for_ty(self.ty)
778772
}
@@ -828,6 +822,38 @@ impl fmt::Display for ValidityConstraint {
828822
}
829823
}
830824

825+
/// Data about a place under investigation.
826+
struct PlaceInfo<Cx: TypeCx> {
827+
/// The type of the place.
828+
ty: Cx::Ty,
829+
/// Whether the place is known to contain valid data.
830+
validity: ValidityConstraint,
831+
/// Whether the place is the scrutinee itself or a subplace of it.
832+
is_scrutinee: bool,
833+
}
834+
835+
impl<Cx: TypeCx> PlaceInfo<Cx> {
836+
fn specialize<'a>(
837+
&'a self,
838+
cx: &'a Cx,
839+
ctor: &'a Constructor<Cx>,
840+
) -> impl Iterator<Item = Self> + ExactSizeIterator + Captures<'a> {
841+
let ctor_sub_tys = cx.ctor_sub_tys(ctor, &self.ty);
842+
let ctor_sub_validity = self.validity.specialize(ctor);
843+
ctor_sub_tys.map(move |ty| PlaceInfo {
844+
ty,
845+
validity: ctor_sub_validity,
846+
is_scrutinee: false,
847+
})
848+
}
849+
}
850+
851+
impl<Cx: TypeCx> Clone for PlaceInfo<Cx> {
852+
fn clone(&self) -> Self {
853+
Self { ty: self.ty.clone(), validity: self.validity, is_scrutinee: self.is_scrutinee }
854+
}
855+
}
856+
831857
/// Represents a pattern-tuple under investigation.
832858
// The three lifetimes are:
833859
// - 'p coming from the input
@@ -1001,10 +1027,9 @@ struct Matrix<'p, Cx: TypeCx> {
10011027
/// each column must have the same type. Each column corresponds to a place within the
10021028
/// scrutinee.
10031029
rows: Vec<MatrixRow<'p, Cx>>,
1004-
/// Track the type of each column/place.
1005-
place_ty: SmallVec<[Cx::Ty; 2]>,
1006-
/// Track for each column/place whether it contains a known valid value.
1007-
place_validity: SmallVec<[ValidityConstraint; 2]>,
1030+
/// Track info about each place. Each place corresponds to a column in `rows`, and their types
1031+
/// must match.
1032+
place_info: SmallVec<[PlaceInfo<Cx>; 2]>,
10081033
/// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
10091034
/// of the file for details on relevancy.
10101035
wildcard_row_is_relevant: bool,
@@ -1032,10 +1057,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10321057
scrut_ty: Cx::Ty,
10331058
scrut_validity: ValidityConstraint,
10341059
) -> Self {
1060+
let place_info = PlaceInfo { ty: scrut_ty, validity: scrut_validity, is_scrutinee: true };
10351061
let mut matrix = Matrix {
10361062
rows: Vec::with_capacity(arms.len()),
1037-
place_ty: smallvec![scrut_ty],
1038-
place_validity: smallvec![scrut_validity],
1063+
place_info: smallvec![place_info],
10391064
wildcard_row_is_relevant: true,
10401065
};
10411066
for (row_id, arm) in arms.iter().enumerate() {
@@ -1051,11 +1076,11 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10511076
matrix
10521077
}
10531078

1054-
fn head_ty(&self) -> Option<&Cx::Ty> {
1055-
self.place_ty.first()
1079+
fn head_place(&self) -> Option<&PlaceInfo<Cx>> {
1080+
self.place_info.first()
10561081
}
10571082
fn column_count(&self) -> usize {
1058-
self.place_ty.len()
1083+
self.place_info.len()
10591084
}
10601085

10611086
fn rows(
@@ -1083,18 +1108,13 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10831108
ctor: &Constructor<Cx>,
10841109
ctor_is_relevant: bool,
10851110
) -> Result<Matrix<'p, Cx>, Cx::Error> {
1086-
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
1087-
let arity = ctor_sub_tys.len();
1088-
let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect();
1089-
let ctor_sub_validity = self.place_validity[0].specialize(ctor);
1090-
let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
1091-
.take(arity)
1092-
.chain(self.place_validity[1..].iter().copied())
1093-
.collect();
1111+
let subfield_place_info = self.place_info[0].specialize(pcx.cx, ctor);
1112+
let arity = subfield_place_info.len();
1113+
let specialized_place_info =
1114+
subfield_place_info.chain(self.place_info[1..].iter().cloned()).collect();
10941115
let mut matrix = Matrix {
10951116
rows: Vec::new(),
1096-
place_ty: specialized_place_ty,
1097-
place_validity: specialized_place_validity,
1117+
place_info: specialized_place_info,
10981118
wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant,
10991119
};
11001120
for (i, row) in self.rows().enumerate() {
@@ -1127,11 +1147,11 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
11271147
.map(|row| row.iter().map(|pat| format!("{pat:?}")).collect())
11281148
.collect();
11291149
pretty_printed_matrix
1130-
.push(self.place_validity.iter().map(|validity| format!("{validity}")).collect());
1150+
.push(self.place_info.iter().map(|place| format!("{}", place.validity)).collect());
11311151

11321152
let column_count = self.column_count();
11331153
assert!(self.rows.iter().all(|row| row.len() == column_count));
1134-
assert!(self.place_validity.len() == column_count);
1154+
assert!(self.place_info.len() == column_count);
11351155
let column_widths: Vec<usize> = (0..column_count)
11361156
.map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
11371157
.collect();
@@ -1432,11 +1452,10 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
14321452
/// - unspecialization, where we lift the results from the previous step into results for this step
14331453
/// (using `apply_constructor` and by updating `row.useful` for each parent row).
14341454
/// This is all explained at the top of the file.
1435-
#[instrument(level = "debug", skip(mcx, is_top_level), ret)]
1455+
#[instrument(level = "debug", skip(mcx), ret)]
14361456
fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14371457
mcx: UsefulnessCtxt<'a, Cx>,
14381458
matrix: &mut Matrix<'p, Cx>,
1439-
is_top_level: bool,
14401459
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
14411460
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
14421461

@@ -1447,7 +1466,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14471466
return Ok(WitnessMatrix::empty());
14481467
}
14491468

1450-
let Some(ty) = matrix.head_ty().cloned() else {
1469+
let Some(place) = matrix.head_place() else {
14511470
// The base case: there are no columns in the matrix. We are morally pattern-matching on ().
14521471
// A row is useful iff it has no (unguarded) rows above it.
14531472
let mut useful = true; // Whether the next row is useful.
@@ -1467,18 +1486,17 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
14671486
};
14681487
};
14691488

1470-
debug!("ty: {ty:?}");
1471-
let pcx = &PlaceCtxt { cx: mcx.tycx, ty: &ty };
1489+
let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later.
1490+
let pcx = &PlaceCtxt { cx: mcx.tycx, ty };
1491+
debug!("ty: {:?}", pcx.ty);
14721492
let ctors_for_ty = pcx.ctors_for_ty()?;
14731493

1474-
// Whether the place/column we are inspecting is known to contain valid data.
1475-
let place_validity = matrix.place_validity[0];
14761494
// We treat match scrutinees of type `!` or `EmptyEnum` differently.
14771495
let is_toplevel_exception =
1478-
is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
1496+
place.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
14791497
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
14801498
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
1481-
let empty_arms_are_unreachable = place_validity.is_known_valid()
1499+
let empty_arms_are_unreachable = place.validity.is_known_valid()
14821500
&& (is_toplevel_exception
14831501
|| mcx.tycx.is_exhaustive_patterns_feature_on()
14841502
|| mcx.tycx.is_min_exhaustive_patterns_feature_on());
@@ -1504,7 +1522,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15041522

15051523
// Decide what constructors to report.
15061524
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. });
1507-
let always_report_all = is_top_level && !is_integers;
1525+
let always_report_all = place.is_scrutinee && !is_integers;
15081526
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
15091527
let report_individual_missing_ctors = always_report_all || !all_missing;
15101528
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
@@ -1525,7 +1543,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15251543
let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
15261544
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?;
15271545
let mut witnesses = ensure_sufficient_stack(|| {
1528-
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
1546+
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix)
15291547
})?;
15301548

15311549
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
@@ -1600,8 +1618,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
16001618
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
16011619
let cx = UsefulnessCtxt { tycx };
16021620
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
1603-
let non_exhaustiveness_witnesses =
1604-
compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
1621+
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix)?;
16051622

16061623
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
16071624
let arm_usefulness: Vec<_> = arms

0 commit comments

Comments
 (0)