Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhaustiveness: remove Matrix.wildcard_row #119667

Merged
merged 2 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_pattern_analysis/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
let relevant_patterns =
self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
for pat in relevant_patterns {
let specialized = pat.specialize(pcx, ctor);
let specialized = pat.specialize(pcx, ctor, ctor_sub_tys);
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
if subpat.is_or_pat() {
column.patterns.extend(subpat.flatten_or_pat())
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_pattern_analysis/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
&self,
pcx: &PlaceCtxt<'_, 'p, Cx>,
other_ctor: &Constructor<Cx>,
ctor_sub_tys: &[Cx::Ty],
) -> SmallVec<[&'p DeconstructedPat<'p, Cx>; 2]> {
let wildcard_sub_tys = || {
let tys = pcx.ctor_sub_tys(other_ctor);
tys.iter()
ctor_sub_tys
.iter()
.map(|ty| DeconstructedPat::wildcard(*ty))
.map(|pat| pcx.mcx.wildcard_arena.alloc(pat) as &_)
.collect()
Expand Down
51 changes: 30 additions & 21 deletions compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ use std::fmt;

use crate::constructor::{Constructor, ConstructorSet};
use crate::pat::{DeconstructedPat, WitnessPat};
use crate::{Captures, MatchArm, MatchCtxt, TypeCx, TypedArena};
use crate::{Captures, MatchArm, MatchCtxt, TypeCx};

use self::ValidityConstraint::*;

Expand Down Expand Up @@ -874,11 +874,12 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
&self,
pcx: &PlaceCtxt<'_, 'p, Cx>,
ctor: &Constructor<Cx>,
ctor_sub_tys: &[Cx::Ty],
ctor_is_relevant: bool,
) -> PatStack<'p, Cx> {
// We pop the head pattern and push the new fields extracted from the arguments of
// `self.head()`.
let mut new_pats = self.head().specialize(pcx, ctor);
let mut new_pats = self.head().specialize(pcx, ctor, ctor_sub_tys);
new_pats.extend_from_slice(&self.pats[1..]);
// `ctor` is relevant for this row if it is the actual constructor of this row, or if the
// row has a wildcard and `ctor` is relevant for wildcards.
Expand Down Expand Up @@ -950,11 +951,12 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> {
&self,
pcx: &PlaceCtxt<'_, 'p, Cx>,
ctor: &Constructor<Cx>,
ctor_sub_tys: &[Cx::Ty],
ctor_is_relevant: bool,
parent_row: usize,
) -> MatrixRow<'p, Cx> {
MatrixRow {
pats: self.pats.pop_head_constructor(pcx, ctor, ctor_is_relevant),
pats: self.pats.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant),
parent_row,
is_under_guard: self.is_under_guard,
useful: false,
Expand Down Expand Up @@ -984,11 +986,13 @@ struct Matrix<'p, Cx: TypeCx> {
/// each column must have the same type. Each column corresponds to a place within the
/// scrutinee.
rows: Vec<MatrixRow<'p, Cx>>,
/// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of
/// each column. This must obey the same invariants as the real rows.
wildcard_row: PatStack<'p, Cx>,
/// Track the type of each column/place.
place_ty: SmallVec<[Cx::Ty; 2]>,
/// Track for each column/place whether it contains a known valid value.
place_validity: SmallVec<[ValidityConstraint; 2]>,
/// Track whether the virtual wildcard row used to compute exhaustiveness is relevant. See top
/// of the file for details on relevancy.
wildcard_row_is_relevant: bool,
}

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

/// Build a new matrix from an iterator of `MatchArm`s.
fn new(
wildcard_arena: &'p TypedArena<DeconstructedPat<'p, Cx>>,
arms: &[MatchArm<'p, Cx>],
scrut_ty: Cx::Ty,
scrut_validity: ValidityConstraint,
) -> Self {
let wild_pattern = wildcard_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
let wildcard_row = PatStack::from_pattern(wild_pattern);
let mut matrix = Matrix {
rows: Vec::with_capacity(arms.len()),
wildcard_row,
place_ty: smallvec![scrut_ty],
place_validity: smallvec![scrut_validity],
wildcard_row_is_relevant: true,
};
for (row_id, arm) in arms.iter().enumerate() {
let v = MatrixRow {
Expand All @@ -1032,10 +1034,10 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
}

fn head_ty(&self) -> Option<Cx::Ty> {
self.wildcard_row.head_opt().map(|pat| pat.ty())
self.place_ty.first().copied()
}
fn column_count(&self) -> usize {
self.wildcard_row.len()
self.place_ty.len()
}

fn rows(
Expand Down Expand Up @@ -1063,17 +1065,24 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
ctor: &Constructor<Cx>,
ctor_is_relevant: bool,
) -> Matrix<'p, Cx> {
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, ctor_is_relevant);
let new_validity = self.place_validity[0].specialize(ctor);
let new_place_validity = std::iter::repeat(new_validity)
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
let specialized_place_ty =
ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).copied().collect();
let ctor_sub_validity = self.place_validity[0].specialize(ctor);
let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
.take(ctor.arity(pcx))
.chain(self.place_validity[1..].iter().copied())
.collect();
let mut matrix =
Matrix { rows: Vec::new(), wildcard_row, place_validity: new_place_validity };
let mut matrix = Matrix {
rows: Vec::new(),
place_ty: specialized_place_ty,
place_validity: specialized_place_validity,
wildcard_row_is_relevant: self.wildcard_row_is_relevant && ctor_is_relevant,
};
for (i, row) in self.rows().enumerate() {
if ctor.is_covered_by(pcx, row.head().ctor()) {
let new_row = row.pop_head_constructor(pcx, ctor, ctor_is_relevant, i);
let new_row =
row.pop_head_constructor(pcx, ctor, ctor_sub_tys, ctor_is_relevant, i);
matrix.expand_and_push(new_row);
}
}
Expand Down Expand Up @@ -1335,7 +1344,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
) -> WitnessMatrix<Cx> {
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));

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

let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
Expand Down
Loading