Skip to content

Commit d8b44d2

Browse files
committed
Auto merge of rust-lang#119667 - Nadrieril:remove-wildcard-row, r=compiler-errors
Exhaustiveness: remove `Matrix.wildcard_row` To compute exhaustiveness, we check whether an extra row with a wildcard added at the end of the match expression would be reachable. We used to store an actual such row of patterns in the `Matrix`, but it's a bit redundant since we know it only contains wildcards. It was kept because we used it to get the type of each column (and relevancy). With this PR, we keep track of the types (and relevancy) directly. This is part of me splitting up rust-lang#119581 for ease of review. r? `@compiler-errors`
2 parents 87e1430 + 50b197c commit d8b44d2

File tree

3 files changed

+35
-24
lines changed

3 files changed

+35
-24
lines changed

compiler/rustc_pattern_analysis/src/lints.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
8383
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
8484
let relevant_patterns =
8585
self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
86+
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
8687
for pat in relevant_patterns {
87-
let specialized = pat.specialize(pcx, ctor);
88+
let specialized = pat.specialize(pcx, ctor, ctor_sub_tys);
8889
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
8990
if subpat.is_or_pat() {
9091
column.patterns.extend(subpat.flatten_or_pat())

compiler/rustc_pattern_analysis/src/pat.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,11 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
8181
&self,
8282
pcx: &PlaceCtxt<'_, 'p, Cx>,
8383
other_ctor: &Constructor<Cx>,
84+
ctor_sub_tys: &[Cx::Ty],
8485
) -> SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]> {
8586
let wildcard_sub_tys = || {
86-
let tys = pcx.ctor_sub_tys(other_ctor);
87-
tys.iter()
87+
ctor_sub_tys
88+
.iter()
8889
.map(|ty| DeconstructedPat::wildcard(*ty))
8990
.map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
9091
.collect()

compiler/rustc_pattern_analysis/src/usefulness.rs

+30-21
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ use std::fmt;
717717

718718
use crate::constructor::{Constructor, ConstructorSet};
719719
use crate::pat::{DeconstructedPat, WitnessPat};
720-
use crate::{Captures, MatchArm, MatchCtxt, TypeCx, TypedArena};
720+
use crate::{Captures, MatchArm, MatchCtxt, TypeCx};
721721

722722
use self::ValidityConstraint::*;
723723

@@ -874,11 +874,12 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
874874
&self,
875875
pcx: &PlaceCtxt<'_, 'p, Cx>,
876876
ctor: &Constructor<Cx>,
877+
ctor_sub_tys: &[Cx::Ty],
877878
ctor_is_relevant: bool,
878879
) -> PatStack<'p, Cx> {
879880
// We pop the head pattern and push the new fields extracted from the arguments of
880881
// `self.head()`.
881-
let mut new_pats = self.head().specialize(pcx, ctor);
882+
let mut new_pats = self.head().specialize(pcx, ctor, ctor_sub_tys);
882883
new_pats.extend_from_slice(&self.pats[1..]);
883884
// `ctor` is relevant for this row if it is the actual constructor of this row, or if the
884885
// row has a wildcard and `ctor` is relevant for wildcards.
@@ -950,11 +951,12 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
950951
&self,
951952
pcx: &PlaceCtxt<'_, 'p, Cx>,
952953
ctor: &Constructor<Cx>,
954+
ctor_sub_tys: &[Cx::Ty],
953955
ctor_is_relevant: bool,
954956
parent_row: usize,
955957
) -> MatrixRow<'p, Cx> {
956958
MatrixRow {
957-
pats: self.pats.pop_head_constructor(pcx, ctor, ctor_is_relevant),
959+
pats: self.pats.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant),
958960
parent_row,
959961
is_under_guard: self.is_under_guard,
960962
useful: false,
@@ -984,11 +986,13 @@ struct Matrix<'p, Cx: TypeCx> {
984986
/// each column must have the same type. Each column corresponds to a place within the
985987
/// scrutinee.
986988
rows: Vec<MatrixRow<'p, Cx>>,
987-
/// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
988-
/// each column. This must obey the same invariants as the real rows.
989-
wildcard_row: PatStack<'p, Cx>,
989+
/// Track the type of each column/place.
990+
place_ty: SmallVec<[Cx::Ty; 2]>,
990991
/// Track for each column/place whether it contains a known valid value.
991992
place_validity: SmallVec<[ValidityConstraint; 2]>,
993+
/// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
994+
/// of the file for details on relevancy.
995+
wildcard_row_is_relevant: bool,
992996
}
993997

994998
impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
@@ -1007,17 +1011,15 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10071011

10081012
/// Build a new matrix from an iterator of `MatchArm`s.
10091013
fn new(
1010-
wildcard_arena: &'p TypedArena<DeconstructedPat<'p, Cx>>,
10111014
arms: &[MatchArm<'p, Cx>],
10121015
scrut_ty: Cx::Ty,
10131016
scrut_validity: ValidityConstraint,
10141017
) -> Self {
1015-
let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
1016-
let wildcard_row = PatStack::from_pattern(wild_pattern);
10171018
let mut matrix = Matrix {
10181019
rows: Vec::with_capacity(arms.len()),
1019-
wildcard_row,
1020+
place_ty: smallvec![scrut_ty],
10201021
place_validity: smallvec![scrut_validity],
1022+
wildcard_row_is_relevant: true,
10211023
};
10221024
for (row_id, arm) in arms.iter().enumerate() {
10231025
let v = MatrixRow {
@@ -1032,10 +1034,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10321034
}
10331035

10341036
fn head_ty(&self) -> Option<Cx::Ty> {
1035-
self.wildcard_row.head_opt().map(|pat| pat.ty())
1037+
self.place_ty.first().copied()
10361038
}
10371039
fn column_count(&self) -> usize {
1038-
self.wildcard_row.len()
1040+
self.place_ty.len()
10391041
}
10401042

10411043
fn rows(
@@ -1063,17 +1065,24 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
10631065
ctor: &Constructor<Cx>,
10641066
ctor_is_relevant: bool,
10651067
) -> Matrix<'p, Cx> {
1066-
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, ctor_is_relevant);
1067-
let new_validity = self.place_validity[0].specialize(ctor);
1068-
let new_place_validity = std::iter::repeat(new_validity)
1068+
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
1069+
let specialized_place_ty =
1070+
ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).copied().collect();
1071+
let ctor_sub_validity = self.place_validity[0].specialize(ctor);
1072+
let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
10691073
.take(ctor.arity(pcx))
10701074
.chain(self.place_validity[1..].iter().copied())
10711075
.collect();
1072-
let mut matrix =
1073-
Matrix { rows: Vec::new(), wildcard_row, place_validity: new_place_validity };
1076+
let mut matrix = Matrix {
1077+
rows: Vec::new(),
1078+
place_ty: specialized_place_ty,
1079+
place_validity: specialized_place_validity,
1080+
wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant,
1081+
};
10741082
for (i, row) in self.rows().enumerate() {
10751083
if ctor.is_covered_by(pcx, row.head().ctor()) {
1076-
let new_row = row.pop_head_constructor(pcx, ctor, ctor_is_relevant, i);
1084+
let new_row =
1085+
row.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant, i);
10771086
matrix.expand_and_push(new_row);
10781087
}
10791088
}
@@ -1335,7 +1344,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
13351344
) -> WitnessMatrix<Cx> {
13361345
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
13371346

1338-
if !matrix.wildcard_row.relevant && matrix.rows().all(|r| !r.pats.relevant) {
1347+
if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) {
13391348
// Here we know that nothing will contribute further to exhaustiveness or usefulness. This
13401349
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
13411350
// the file for details.
@@ -1356,7 +1365,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
13561365
}
13571366
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
13581367
// irrelevant.
1359-
return if matrix.wildcard_row.relevant {
1368+
return if matrix.wildcard_row_is_relevant {
13601369
WitnessMatrix::unit_witness()
13611370
} else {
13621371
// We choose to not report anything here; see at the top for details.
@@ -1466,7 +1475,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
14661475
scrut_ty: Cx::Ty,
14671476
scrut_validity: ValidityConstraint,
14681477
) -> UsefulnessReport<'p, Cx> {
1469-
let mut matrix = Matrix::new(cx.wildcard_arena, arms, scrut_ty, scrut_validity);
1478+
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
14701479
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true);
14711480

14721481
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();

0 commit comments

Comments
 (0)