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::fx::FxHashSet;
5 use rustc_span::hygiene::DesugaringKind;
6 use rustc_span::symbol::Ident;
9 use std::iter::{Enumerate, ExactSizeIterator};
11 pub struct EnumerateAndAdjust<I> {
12 enumerate: Enumerate<I>,
17 impl<I> Iterator for EnumerateAndAdjust<I>
21 type Item = (usize, <I as Iterator>::Item);
23 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
26 .map(|(i, elem)| (if i < self.gap_pos { i } else { i + self.gap_len }, elem))
29 fn size_hint(&self) -> (usize, Option<usize>) {
30 self.enumerate.size_hint()
34 pub trait EnumerateAndAdjustIterator {
35 fn enumerate_and_adjust(
38 gap_pos: Option<usize>,
39 ) -> EnumerateAndAdjust<Self>
44 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
45 fn enumerate_and_adjust(
48 gap_pos: Option<usize>,
49 ) -> EnumerateAndAdjust<Self>
53 let actual_len = self.len();
55 enumerate: self.enumerate(),
56 gap_pos: gap_pos.unwrap_or(expected_len),
57 gap_len: expected_len - actual_len,
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);
73 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
74 /// `match foo() { Some(a) => (), None => () }`.
76 /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
77 pub fn each_binding_or_first(
79 f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident),
81 self.walk(|p| match &p.kind {
83 ps[0].each_binding_or_first(f);
86 PatKind::Binding(bm, _, ident, _) => {
87 f(*bm, p.hir_id, p.span, *ident);
94 pub fn simple_ident(&self) -> Option<Ident> {
97 hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
106 /// Returns variants that are necessary to exist for the pattern to match.
107 pub fn necessary_variants(&self) -> Vec<DefId> {
108 let mut variants = vec![];
109 self.walk(|p| match &p.kind {
110 PatKind::Or(_) => false,
111 PatKind::Path(hir::QPath::Resolved(_, path))
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) =
123 // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
125 let mut duplicates = FxHashSet::default();
126 variants.retain(|def_id| duplicates.insert(*def_id));
130 /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
131 /// yes whether it contains mutable or just immutables ones.
133 // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
134 // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
135 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
136 let mut result = None;
137 self.each_binding(|annotation, _, _, _| match annotation {
138 hir::BindingAnnotation::Ref => match result {
139 None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
142 hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),
148 /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
149 pub fn for_loop_some(&self) -> Option<&Self> {
150 if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
151 if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
152 return Some(pat_field.pat);