Skip to content

Commit 60dfd20

Browse files
committed
Make PatternColumn part of the public API
1 parent 44c3195 commit 60dfd20

File tree

4 files changed

+101
-90
lines changed

4 files changed

+101
-90
lines changed

compiler/rustc_pattern_analysis/src/constructor.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -848,10 +848,10 @@ pub enum ConstructorSet<Cx: TypeCx> {
848848
/// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
849849
/// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4.
850850
#[derive(Debug)]
851-
pub(crate) struct SplitConstructorSet<Cx: TypeCx> {
852-
pub(crate) present: SmallVec<[Constructor<Cx>; 1]>,
853-
pub(crate) missing: Vec<Constructor<Cx>>,
854-
pub(crate) missing_empty: Vec<Constructor<Cx>>,
851+
pub struct SplitConstructorSet<Cx: TypeCx> {
852+
pub present: SmallVec<[Constructor<Cx>; 1]>,
853+
pub missing: Vec<Constructor<Cx>>,
854+
pub missing_empty: Vec<Constructor<Cx>>,
855855
}
856856

857857
impl<Cx: TypeCx> ConstructorSet<Cx> {
@@ -860,7 +860,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
860860
/// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
861861
/// and its invariants.
862862
#[instrument(level = "debug", skip(self, ctors), ret)]
863-
pub(crate) fn split<'a>(
863+
pub fn split<'a>(
864864
&self,
865865
ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
866866
) -> SplitConstructorSet<Cx>

compiler/rustc_pattern_analysis/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod errors;
66
#[cfg(feature = "rustc")]
77
pub(crate) mod lints;
88
pub mod pat;
9+
pub mod pat_column;
910
#[cfg(feature = "rustc")]
1011
pub mod rustc;
1112
pub mod usefulness;
@@ -67,8 +68,9 @@ use rustc_span::ErrorGuaranteed;
6768

6869
use crate::constructor::{Constructor, ConstructorSet, IntRange};
6970
#[cfg(feature = "rustc")]
70-
use crate::lints::{lint_nonexhaustive_missing_variants, PatternColumn};
71+
use crate::lints::lint_nonexhaustive_missing_variants;
7172
use crate::pat::DeconstructedPat;
73+
use crate::pat_column::PatternColumn;
7274
#[cfg(feature = "rustc")]
7375
use crate::rustc::RustcMatchCheckCtxt;
7476
#[cfg(feature = "rustc")]

compiler/rustc_pattern_analysis/src/lints.rs

+3-84
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,11 @@
11
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
22
use rustc_span::ErrorGuaranteed;
33

4-
use crate::constructor::{Constructor, SplitConstructorSet};
4+
use crate::constructor::Constructor;
55
use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
6-
use crate::pat::{DeconstructedPat, PatOrWild};
6+
use crate::pat_column::PatternColumn;
77
use crate::rustc::{RevealedTy, RustcMatchCheckCtxt, WitnessPat};
8-
use crate::{MatchArm, TypeCx};
9-
10-
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
11-
/// inspect the same subvalue/place".
12-
/// This is used to traverse patterns column-by-column for lints. Despite similarities with the
13-
/// algorithm in [`crate::usefulness`], this does a different traversal. Notably this is linear in
14-
/// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential
15-
/// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately.
16-
///
17-
/// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
18-
///
19-
/// This is not used in the usefulness algorithm; only in lints.
20-
#[derive(Debug)]
21-
pub(crate) struct PatternColumn<'p, Cx: TypeCx> {
22-
patterns: Vec<&'p DeconstructedPat<'p, Cx>>,
23-
}
24-
25-
impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
26-
pub(crate) fn new(arms: &[MatchArm<'p, Cx>]) -> Self {
27-
let patterns = Vec::with_capacity(arms.len());
28-
let mut column = PatternColumn { patterns };
29-
for arm in arms {
30-
column.expand_and_push(PatOrWild::Pat(arm.pat));
31-
}
32-
column
33-
}
34-
/// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns.
35-
/// Internal method, prefer [`PatternColumn::new`].
36-
fn expand_and_push(&mut self, pat: PatOrWild<'p, Cx>) {
37-
// We flatten or-patterns and skip algorithm-generated wildcards.
38-
if pat.is_or_pat() {
39-
self.patterns.extend(
40-
pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()),
41-
)
42-
} else if let Some(pat) = pat.as_pat() {
43-
self.patterns.push(pat)
44-
}
45-
}
46-
47-
fn head_ty(&self) -> Option<&Cx::Ty> {
48-
self.patterns.first().map(|pat| pat.ty())
49-
}
50-
51-
/// Do constructor splitting on the constructors of the column.
52-
fn analyze_ctors(&self, cx: &Cx, ty: &Cx::Ty) -> Result<SplitConstructorSet<Cx>, Cx::Error> {
53-
let column_ctors = self.patterns.iter().map(|p| p.ctor());
54-
let ctors_for_ty = cx.ctors_for_ty(ty)?;
55-
Ok(ctors_for_ty.split(column_ctors))
56-
}
57-
58-
/// Does specialization: given a constructor, this takes the patterns from the column that match
59-
/// the constructor, and outputs their fields.
60-
/// This returns one column per field of the constructor. They usually all have the same length
61-
/// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns
62-
/// which may change the lengths.
63-
fn specialize(
64-
&self,
65-
cx: &Cx,
66-
ty: &Cx::Ty,
67-
ctor: &Constructor<Cx>,
68-
) -> Vec<PatternColumn<'p, Cx>> {
69-
let arity = ctor.arity(cx, ty);
70-
if arity == 0 {
71-
return Vec::new();
72-
}
73-
74-
// We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
75-
// columns may have different lengths in the presence of or-patterns (this is why we can't
76-
// reuse `Matrix`).
77-
let mut specialized_columns: Vec<_> =
78-
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
79-
let relevant_patterns =
80-
self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()));
81-
for pat in relevant_patterns {
82-
let specialized = pat.specialize(ctor, arity);
83-
for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) {
84-
column.expand_and_push(subpat);
85-
}
86-
}
87-
specialized_columns
88-
}
89-
}
8+
use crate::MatchArm;
909

9110
/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
9211
/// in a given column.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use crate::constructor::{Constructor, SplitConstructorSet};
2+
use crate::pat::{DeconstructedPat, PatOrWild};
3+
use crate::{Captures, MatchArm, TypeCx};
4+
5+
/// A column of patterns in a match, where a column is the intuitive notion of "subpatterns that
6+
/// inspect the same subvalue/place".
7+
/// This is used to traverse patterns column-by-column for lints. Despite similarities with the
8+
/// algorithm in [`crate::usefulness`], this does a different traversal. Notably this is linear in
9+
/// the depth of patterns, whereas `compute_exhaustiveness_and_usefulness` is worst-case exponential
10+
/// (exhaustiveness is NP-complete). The core difference is that we treat sub-columns separately.
11+
///
12+
/// This is not used in the usefulness algorithm; only in lints.
13+
#[derive(Debug)]
14+
pub struct PatternColumn<'p, Cx: TypeCx> {
15+
/// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
16+
patterns: Vec<&'p DeconstructedPat<'p, Cx>>,
17+
}
18+
19+
impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
20+
pub fn new(arms: &[MatchArm<'p, Cx>]) -> Self {
21+
let patterns = Vec::with_capacity(arms.len());
22+
let mut column = PatternColumn { patterns };
23+
for arm in arms {
24+
column.expand_and_push(PatOrWild::Pat(arm.pat));
25+
}
26+
column
27+
}
28+
/// Pushes a pattern onto the column, expanding any or-patterns into its subpatterns.
29+
/// Internal method, prefer [`PatternColumn::new`].
30+
fn expand_and_push(&mut self, pat: PatOrWild<'p, Cx>) {
31+
// We flatten or-patterns and skip algorithm-generated wildcards.
32+
if pat.is_or_pat() {
33+
self.patterns.extend(
34+
pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()),
35+
)
36+
} else if let Some(pat) = pat.as_pat() {
37+
self.patterns.push(pat)
38+
}
39+
}
40+
41+
pub fn head_ty(&self) -> Option<&Cx::Ty> {
42+
self.patterns.first().map(|pat| pat.ty())
43+
}
44+
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
45+
self.patterns.iter().copied()
46+
}
47+
48+
/// Do constructor splitting on the constructors of the column.
49+
pub fn analyze_ctors(
50+
&self,
51+
cx: &Cx,
52+
ty: &Cx::Ty,
53+
) -> Result<SplitConstructorSet<Cx>, Cx::Error> {
54+
let column_ctors = self.patterns.iter().map(|p| p.ctor());
55+
let ctors_for_ty = cx.ctors_for_ty(ty)?;
56+
Ok(ctors_for_ty.split(column_ctors))
57+
}
58+
59+
/// Does specialization: given a constructor, this takes the patterns from the column that match
60+
/// the constructor, and outputs their fields.
61+
/// This returns one column per field of the constructor. They usually all have the same length
62+
/// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns
63+
/// which may change the lengths.
64+
pub fn specialize(
65+
&self,
66+
cx: &Cx,
67+
ty: &Cx::Ty,
68+
ctor: &Constructor<Cx>,
69+
) -> Vec<PatternColumn<'p, Cx>> {
70+
let arity = ctor.arity(cx, ty);
71+
if arity == 0 {
72+
return Vec::new();
73+
}
74+
75+
// We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
76+
// columns may have different lengths in the presence of or-patterns (this is why we can't
77+
// reuse `Matrix`).
78+
let mut specialized_columns: Vec<_> =
79+
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
80+
let relevant_patterns =
81+
self.patterns.iter().filter(|pat| ctor.is_covered_by(cx, pat.ctor()));
82+
for pat in relevant_patterns {
83+
let specialized = pat.specialize(ctor, arity);
84+
for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) {
85+
column.expand_and_push(subpat);
86+
}
87+
}
88+
specialized_columns
89+
}
90+
}

0 commit comments

Comments
 (0)