rustc_hir/
pat_util.rs
1use std::iter::Enumerate;
2
3use rustc_span::{Ident, Span};
4
5use crate::def::{CtorOf, DefKind, Res};
6use crate::def_id::{DefId, DefIdSet};
7use crate::hir::{self, BindingMode, ByRef, HirId, PatKind};
8
9pub struct EnumerateAndAdjust<I> {
10 enumerate: Enumerate<I>,
11 gap_pos: usize,
12 gap_len: usize,
13}
14
15impl<I> Iterator for EnumerateAndAdjust<I>
16where
17 I: Iterator,
18{
19 type Item = (usize, <I as Iterator>::Item);
20
21 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
22 self.enumerate
23 .next()
24 .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
25 }
26
27 fn size_hint(&self) -> (usize, Option<usize>) {
28 self.enumerate.size_hint()
29 }
30}
31
32pub trait EnumerateAndAdjustIterator {
33 fn enumerate_and_adjust(
34 self,
35 expected_len: usize,
36 gap_pos: hir::DotDotPos,
37 ) -> EnumerateAndAdjust<Self>
38 where
39 Self: Sized;
40}
41
42impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
43 fn enumerate_and_adjust(
44 self,
45 expected_len: usize,
46 gap_pos: hir::DotDotPos,
47 ) -> EnumerateAndAdjust<Self>
48 where
49 Self: Sized,
50 {
51 let actual_len = self.len();
52 EnumerateAndAdjust {
53 enumerate: self.enumerate(),
54 gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
55 gap_len: expected_len - actual_len,
56 }
57 }
58}
59
60impl hir::Pat<'_> {
61 pub fn each_binding(&self, mut f: impl FnMut(hir::BindingMode, HirId, Span, Ident)) {
64 self.walk_always(|p| {
65 if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
66 f(binding_mode, p.hir_id, p.span, ident);
67 }
68 });
69 }
70
71 pub fn each_binding_or_first(&self, f: &mut impl FnMut(hir::BindingMode, HirId, Span, Ident)) {
78 self.walk(|p| match &p.kind {
79 PatKind::Or(ps) => {
80 for p in *ps {
81 if !p.is_never_pattern() {
82 p.each_binding_or_first(f);
83 break;
84 }
85 }
86 false
87 }
88 PatKind::Binding(bm, _, ident, _) => {
89 f(*bm, p.hir_id, p.span, *ident);
90 true
91 }
92 _ => true,
93 })
94 }
95
96 pub fn simple_ident(&self) -> Option<Ident> {
97 match self.kind {
98 PatKind::Binding(BindingMode(ByRef::No, _), _, ident, None) => Some(ident),
99 _ => None,
100 }
101 }
102
103 pub fn necessary_variants(&self) -> Vec<DefId> {
105 let mut variants = vec![];
106 self.walk(|p| match &p.kind {
107 PatKind::Or(_) => false,
108 PatKind::Expr(hir::PatExpr {
109 kind: hir::PatExprKind::Path(hir::QPath::Resolved(_, path)),
110 ..
111 })
112 | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
113 | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
114 if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
115 path.res
116 {
117 variants.push(id);
118 }
119 true
120 }
121 _ => true,
122 });
123 let mut duplicates = DefIdSet::default();
126 variants.retain(|def_id| duplicates.insert(*def_id));
127 variants
128 }
129
130 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
136 let mut result = None;
137 self.each_binding(|annotation, _, _, _| match annotation {
138 hir::BindingMode::REF if result.is_none() => result = Some(hir::Mutability::Not),
139 hir::BindingMode::REF_MUT => result = Some(hir::Mutability::Mut),
140 _ => {}
141 });
142 result
143 }
144}