1 use crate::def::{CtorOf, DefKind, Res};
2 use crate::def_id::DefId;
3 use crate::hir::{self, HirId, PatKind};
4 use rustc_span::symbol::Ident;
7 use std::iter::{Enumerate, ExactSizeIterator};
9 pub struct EnumerateAndAdjust<I> {
10 enumerate: Enumerate<I>,
15 impl<I> Iterator for EnumerateAndAdjust<I>
19 type Item = (usize, <I as Iterator>::Item);
21 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
24 .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
27 fn size_hint(&self) -> (usize, Option<usize>) {
28 self.enumerate.size_hint()
32 pub trait EnumerateAndAdjustIterator {
33 fn enumerate_and_adjust(
36 gap_pos: Option<usize>,
37 ) -> EnumerateAndAdjust<Self>
42 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
43 fn enumerate_and_adjust(
46 gap_pos: Option<usize>,
47 ) -> EnumerateAndAdjust<Self>
51 let actual_len = self.len();
53 enumerate: self.enumerate(),
54 gap_pos: gap_pos.unwrap_or(expected_len),
55 gap_len: expected_len - actual_len,
61 pub fn is_refutable(&self) -> bool {
65 | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => {
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,
75 PatKind::Slice(..) => true,
80 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
81 /// `match foo() { Some(a) => (), None => () }`
82 pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
83 self.walk_always(|p| {
84 if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
85 f(binding_mode, p.hir_id, p.span, ident);
90 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
91 /// `match foo() { Some(a) => (), None => () }`.
93 /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
94 pub fn each_binding_or_first(
96 f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident),
98 self.walk(|p| match &p.kind {
100 ps[0].each_binding_or_first(f);
103 PatKind::Binding(bm, _, ident, _) => {
104 f(*bm, p.hir_id, p.span, *ident);
111 /// Checks if the pattern contains any patterns that bind something to
112 /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
113 pub fn contains_bindings(&self) -> bool {
114 self.satisfies(|p| match p.kind {
115 PatKind::Binding(..) => true,
120 /// Checks if the pattern contains any patterns that bind something to
121 /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
122 pub fn contains_bindings_or_wild(&self) -> bool {
123 self.satisfies(|p| match p.kind {
124 PatKind::Binding(..) | PatKind::Wild => true,
129 /// Checks if the pattern satisfies the given predicate on some sub-pattern.
130 fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool {
131 let mut satisfies = false;
132 self.walk_short(|p| {
135 false // Found one, can short circuit now.
143 pub fn simple_ident(&self) -> Option<Ident> {
146 hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
155 /// Returns variants that are necessary to exist for the pattern to match.
156 pub fn necessary_variants(&self) -> Vec<DefId> {
157 let mut variants = vec![];
158 self.walk(|p| match &p.kind {
159 PatKind::Or(_) => false,
160 PatKind::Path(hir::QPath::Resolved(_, path))
161 | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
162 | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
163 if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
177 /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
178 /// yes whether it contains mutable or just immutables ones.
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.
182 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
183 let mut result = None;
184 self.each_binding(|annotation, _, _, _| match annotation {
185 hir::BindingAnnotation::Ref => match result {
186 None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
189 hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),