]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use crate::def::{CtorOf, DefKind, Res}; |
2 | use crate::def_id::DefId; | |
9fa01778 | 3 | use crate::hir::{self, HirId, PatKind}; |
74b04a01 | 4 | use rustc_ast::ast; |
dfeec247 | 5 | use rustc_span::Span; |
223e47cc | 6 | |
3157f602 | 7 | use std::iter::{Enumerate, ExactSizeIterator}; |
92a42be0 | 8 | |
3157f602 XL |
9 | pub struct EnumerateAndAdjust<I> { |
10 | enumerate: Enumerate<I>, | |
11 | gap_pos: usize, | |
12 | gap_len: usize, | |
13 | } | |
14 | ||
dfeec247 XL |
15 | impl<I> Iterator for EnumerateAndAdjust<I> |
16 | where | |
17 | I: Iterator, | |
18 | { | |
3157f602 XL |
19 | type Item = (usize, <I as Iterator>::Item); |
20 | ||
21 | fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> { | |
dfeec247 XL |
22 | self.enumerate |
23 | .next() | |
24 | .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem)) | |
3157f602 | 25 | } |
0531ce1d XL |
26 | |
27 | fn size_hint(&self) -> (usize, Option<usize>) { | |
28 | self.enumerate.size_hint() | |
29 | } | |
3157f602 XL |
30 | } |
31 | ||
32 | pub trait EnumerateAndAdjustIterator { | |
dfeec247 XL |
33 | fn enumerate_and_adjust( |
34 | self, | |
35 | expected_len: usize, | |
36 | gap_pos: Option<usize>, | |
37 | ) -> EnumerateAndAdjust<Self> | |
38 | where | |
39 | Self: Sized; | |
3157f602 XL |
40 | } |
41 | ||
42 | impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T { | |
dfeec247 XL |
43 | fn enumerate_and_adjust( |
44 | self, | |
45 | expected_len: usize, | |
46 | gap_pos: Option<usize>, | |
47 | ) -> EnumerateAndAdjust<Self> | |
48 | where | |
49 | Self: Sized, | |
50 | { | |
3157f602 XL |
51 | let actual_len = self.len(); |
52 | EnumerateAndAdjust { | |
53 | enumerate: self.enumerate(), | |
8faf50e0 | 54 | gap_pos: gap_pos.unwrap_or(expected_len), |
3157f602 XL |
55 | gap_len: expected_len - actual_len, |
56 | } | |
57 | } | |
223e47cc LB |
58 | } |
59 | ||
dfeec247 | 60 | impl hir::Pat<'_> { |
476ff2be | 61 | pub fn is_refutable(&self) -> bool { |
e74abb32 | 62 | match self.kind { |
dfeec247 XL |
63 | PatKind::Lit(_) |
64 | | PatKind::Range(..) | |
ba9703b0 XL |
65 | | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => { |
66 | true | |
67 | } | |
dfeec247 XL |
68 | |
69 | PatKind::Path(hir::QPath::Resolved(_, ref path)) | |
70 | | PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | |
71 | | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res { | |
72 | Res::Def(DefKind::Variant, _) => true, | |
73 | _ => false, | |
74 | }, | |
476ff2be | 75 | PatKind::Slice(..) => true, |
dfeec247 | 76 | _ => false, |
1a4d82fc | 77 | } |
1a4d82fc | 78 | } |
1a4d82fc | 79 | |
476ff2be SL |
80 | /// Call `f` on every "binding" in a pattern, e.g., on `a` in |
81 | /// `match foo() { Some(a) => (), None => () }` | |
e74abb32 | 82 | pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) { |
dfeec247 | 83 | self.walk_always(|p| { |
e74abb32 | 84 | if let PatKind::Binding(binding_mode, _, ident, _) = p.kind { |
8faf50e0 | 85 | f(binding_mode, p.hir_id, p.span, ident); |
476ff2be | 86 | } |
476ff2be SL |
87 | }); |
88 | } | |
1a4d82fc | 89 | |
e74abb32 XL |
90 | /// Call `f` on every "binding" in a pattern, e.g., on `a` in |
91 | /// `match foo() { Some(a) => (), None => () }`. | |
92 | /// | |
93 | /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited. | |
94 | pub fn each_binding_or_first( | |
95 | &self, | |
96 | f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident), | |
97 | ) { | |
98 | self.walk(|p| match &p.kind { | |
99 | PatKind::Or(ps) => { | |
100 | ps[0].each_binding_or_first(f); | |
101 | false | |
dfeec247 XL |
102 | } |
103 | PatKind::Binding(bm, _, ident, _) => { | |
e74abb32 XL |
104 | f(*bm, p.hir_id, p.span, *ident); |
105 | true | |
106 | } | |
107 | _ => true, | |
108 | }) | |
109 | } | |
110 | ||
476ff2be | 111 | /// Checks if the pattern contains any patterns that bind something to |
0731742a | 112 | /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`. |
476ff2be | 113 | pub fn contains_bindings(&self) -> bool { |
e74abb32 XL |
114 | self.satisfies(|p| match p.kind { |
115 | PatKind::Binding(..) => true, | |
116 | _ => false, | |
117 | }) | |
476ff2be | 118 | } |
c34b1796 | 119 | |
476ff2be | 120 | /// Checks if the pattern contains any patterns that bind something to |
0731742a | 121 | /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`, |
476ff2be | 122 | pub fn contains_bindings_or_wild(&self) -> bool { |
e74abb32 XL |
123 | self.satisfies(|p| match p.kind { |
124 | PatKind::Binding(..) | PatKind::Wild => true, | |
125 | _ => false, | |
126 | }) | |
127 | } | |
128 | ||
129 | /// Checks if the pattern satisfies the given predicate on some sub-pattern. | |
dfeec247 | 130 | fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool { |
e74abb32 XL |
131 | let mut satisfies = false; |
132 | self.walk_short(|p| { | |
133 | if pred(p) { | |
134 | satisfies = true; | |
135 | false // Found one, can short circuit now. | |
136 | } else { | |
137 | true | |
3157f602 | 138 | } |
476ff2be | 139 | }); |
e74abb32 | 140 | satisfies |
476ff2be | 141 | } |
c34b1796 | 142 | |
8faf50e0 | 143 | pub fn simple_ident(&self) -> Option<ast::Ident> { |
e74abb32 | 144 | match self.kind { |
ba9703b0 XL |
145 | PatKind::Binding( |
146 | hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, | |
147 | _, | |
148 | ident, | |
149 | None, | |
150 | ) => Some(ident), | |
94b46f34 XL |
151 | _ => None, |
152 | } | |
153 | } | |
154 | ||
9fa01778 | 155 | /// Returns variants that are necessary to exist for the pattern to match. |
476ff2be SL |
156 | pub fn necessary_variants(&self) -> Vec<DefId> { |
157 | let mut variants = vec![]; | |
e74abb32 XL |
158 | self.walk(|p| match &p.kind { |
159 | PatKind::Or(_) => false, | |
dfeec247 XL |
160 | PatKind::Path(hir::QPath::Resolved(_, path)) |
161 | | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..) | |
162 | | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => { | |
ba9703b0 XL |
163 | if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) = |
164 | path.res | |
e74abb32 XL |
165 | { |
166 | variants.push(id); | |
476ff2be | 167 | } |
e74abb32 | 168 | true |
476ff2be | 169 | } |
e74abb32 | 170 | _ => true, |
476ff2be SL |
171 | }); |
172 | variants.sort(); | |
173 | variants.dedup(); | |
174 | variants | |
175 | } | |
62682a34 | 176 | |
ea8adc8c XL |
177 | /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if |
178 | /// yes whether it contains mutable or just immutables ones. | |
9fa01778 XL |
179 | // |
180 | // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but | |
181 | // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848. | |
3b2f2976 | 182 | pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> { |
476ff2be | 183 | let mut result = None; |
dfeec247 XL |
184 | self.each_binding(|annotation, _, _, _| match annotation { |
185 | hir::BindingAnnotation::Ref => match result { | |
186 | None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not), | |
e74abb32 | 187 | _ => {} |
dfeec247 XL |
188 | }, |
189 | hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut), | |
190 | _ => {} | |
476ff2be SL |
191 | }); |
192 | result | |
193 | } | |
194 | } |