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