]> git.proxmox.com Git - rustc.git/blame - src/librustc_hir/pat_util.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / librustc_hir / pat_util.rs
CommitLineData
dfeec247
XL
1use crate::def::{CtorOf, DefKind, Res};
2use crate::def_id::DefId;
9fa01778 3use crate::hir::{self, HirId, PatKind};
74b04a01 4use rustc_ast::ast;
dfeec247 5use rustc_span::Span;
223e47cc 6
3157f602 7use std::iter::{Enumerate, ExactSizeIterator};
92a42be0 8
3157f602
XL
9pub struct EnumerateAndAdjust<I> {
10 enumerate: Enumerate<I>,
11 gap_pos: usize,
12 gap_len: usize,
13}
14
dfeec247
XL
15impl<I> Iterator for EnumerateAndAdjust<I>
16where
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
32pub 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
42impl<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 60impl 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}