]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir/src/pat_util.rs
Rollup merge of #106608 - compiler-errors:missing-generics-verbose, r=estebank
[rust.git] / compiler / rustc_hir / src / pat_util.rs
1 use crate::def::{CtorOf, DefKind, Res};
2 use crate::def_id::DefId;
3 use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_span::hygiene::DesugaringKind;
6 use rustc_span::symbol::Ident;
7 use rustc_span::Span;
8
9 use std::iter::Enumerate;
10
11 pub struct EnumerateAndAdjust<I> {
12     enumerate: Enumerate<I>,
13     gap_pos: usize,
14     gap_len: usize,
15 }
16
17 impl<I> Iterator for EnumerateAndAdjust<I>
18 where
19     I: Iterator,
20 {
21     type Item = (usize, <I as Iterator>::Item);
22
23     fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
24         self.enumerate
25             .next()
26             .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
27     }
28
29     fn size_hint(&self) -> (usize, Option<usize>) {
30         self.enumerate.size_hint()
31     }
32 }
33
34 pub trait EnumerateAndAdjustIterator {
35     fn enumerate_and_adjust(
36         self,
37         expected_len: usize,
38         gap_pos: hir::DotDotPos,
39     ) -> EnumerateAndAdjust<Self>
40     where
41         Self: Sized;
42 }
43
44 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
45     fn enumerate_and_adjust(
46         self,
47         expected_len: usize,
48         gap_pos: hir::DotDotPos,
49     ) -> EnumerateAndAdjust<Self>
50     where
51         Self: Sized,
52     {
53         let actual_len = self.len();
54         EnumerateAndAdjust {
55             enumerate: self.enumerate(),
56             gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
57             gap_len: expected_len - actual_len,
58         }
59     }
60 }
61
62 impl hir::Pat<'_> {
63     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
64     /// `match foo() { Some(a) => (), None => () }`
65     pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
66         self.walk_always(|p| {
67             if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
68                 f(binding_mode, p.hir_id, p.span, ident);
69             }
70         });
71     }
72
73     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
74     /// `match foo() { Some(a) => (), None => () }`.
75     ///
76     /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
77     pub fn each_binding_or_first(
78         &self,
79         f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident),
80     ) {
81         self.walk(|p| match &p.kind {
82             PatKind::Or(ps) => {
83                 ps[0].each_binding_or_first(f);
84                 false
85             }
86             PatKind::Binding(bm, _, ident, _) => {
87                 f(*bm, p.hir_id, p.span, *ident);
88                 true
89             }
90             _ => true,
91         })
92     }
93
94     pub fn simple_ident(&self) -> Option<Ident> {
95         match self.kind {
96             PatKind::Binding(BindingAnnotation(ByRef::No, _), _, ident, None) => Some(ident),
97             _ => None,
98         }
99     }
100
101     /// Returns variants that are necessary to exist for the pattern to match.
102     pub fn necessary_variants(&self) -> Vec<DefId> {
103         let mut variants = vec![];
104         self.walk(|p| match &p.kind {
105             PatKind::Or(_) => false,
106             PatKind::Path(hir::QPath::Resolved(_, path))
107             | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
108             | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
109                 if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
110                     path.res
111                 {
112                     variants.push(id);
113                 }
114                 true
115             }
116             _ => true,
117         });
118         // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
119         // the bounds
120         let mut duplicates = FxHashSet::default();
121         variants.retain(|def_id| duplicates.insert(*def_id));
122         variants
123     }
124
125     /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
126     /// yes whether it contains mutable or just immutables ones.
127     //
128     // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
129     // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
130     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
131         let mut result = None;
132         self.each_binding(|annotation, _, _, _| match annotation {
133             hir::BindingAnnotation::REF if result.is_none() => result = Some(hir::Mutability::Not),
134             hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut),
135             _ => {}
136         });
137         result
138     }
139
140     /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
141     pub fn for_loop_some(&self) -> Option<&Self> {
142         if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
143             if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
144                 return Some(pat_field.pat);
145             }
146         }
147         None
148     }
149 }