|
1 | 1 | use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; |
2 | 2 | use rustc_span::ErrorGuaranteed; |
3 | 3 |
|
4 | | -use crate::constructor::{Constructor, SplitConstructorSet}; |
| 4 | +use crate::constructor::Constructor; |
5 | 5 | use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered}; |
6 | | -use crate::pat::{DeconstructedPat, PatOrWild}; |
| 6 | +use crate::pat_column::PatternColumn; |
7 | 7 | 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; |
90 | 9 |
|
91 | 10 | /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned |
92 | 11 | /// in a given column. |
|
0 commit comments