|
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