1 use crate::hir::def::{CtorOf, Res, DefKind};
2 use crate::hir::def_id::DefId;
3 use crate::hir::{self, HirId, PatKind};
7 use std::iter::{Enumerate, ExactSizeIterator};
9 pub struct EnumerateAndAdjust<I> {
10 enumerate: Enumerate<I>,
15 impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
16 type Item = (usize, <I as Iterator>::Item);
18 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
19 self.enumerate.next().map(|(i, elem)| {
20 (if i < self.gap_pos { i } else { i + self.gap_len }, elem)
24 fn size_hint(&self) -> (usize, Option<usize>) {
25 self.enumerate.size_hint()
29 pub trait EnumerateAndAdjustIterator {
30 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
31 -> EnumerateAndAdjust<Self> where Self: Sized;
34 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
35 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
36 -> EnumerateAndAdjust<Self> where Self: Sized {
37 let actual_len = self.len();
39 enumerate: self.enumerate(),
40 gap_pos: gap_pos.unwrap_or(expected_len),
41 gap_len: expected_len - actual_len,
47 pub fn is_refutable(&self) -> bool {
51 PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
52 PatKind::Path(hir::QPath::TypeRelative(..)) => true,
54 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
55 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
56 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
58 Res::Def(DefKind::Variant, _) => true,
62 PatKind::Slice(..) => true,
67 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
68 /// `match foo() { Some(a) => (), None => () }`
69 pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) {
71 if let PatKind::Binding(binding_mode, _, ident, _) = p.kind {
72 f(binding_mode, p.hir_id, p.span, ident);
78 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
79 /// `match foo() { Some(a) => (), None => () }`.
81 /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
82 pub fn each_binding_or_first(
84 f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
86 self.walk(|p| match &p.kind {
88 ps[0].each_binding_or_first(f);
91 PatKind::Binding(bm, _, ident, _) => {
92 f(*bm, p.hir_id, p.span, *ident);
99 /// Checks if the pattern contains any patterns that bind something to
100 /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
101 pub fn contains_bindings(&self) -> bool {
102 self.satisfies(|p| match p.kind {
103 PatKind::Binding(..) => true,
108 /// Checks if the pattern contains any patterns that bind something to
109 /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
110 pub fn contains_bindings_or_wild(&self) -> bool {
111 self.satisfies(|p| match p.kind {
112 PatKind::Binding(..) | PatKind::Wild => true,
117 /// Checks if the pattern satisfies the given predicate on some sub-pattern.
118 fn satisfies(&self, pred: impl Fn(&Self) -> bool) -> bool {
119 let mut satisfies = false;
120 self.walk_short(|p| {
123 false // Found one, can short circuit now.
131 pub fn simple_ident(&self) -> Option<ast::Ident> {
133 PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) |
134 PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, None) => Some(ident),
139 /// Returns variants that are necessary to exist for the pattern to match.
140 pub fn necessary_variants(&self) -> Vec<DefId> {
141 let mut variants = vec![];
142 self.walk(|p| match &p.kind {
143 PatKind::Or(_) => false,
144 PatKind::Path(hir::QPath::Resolved(_, path)) |
145 PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..) |
146 PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
147 if let Res::Def(DefKind::Variant, id)
148 | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id)
162 /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
163 /// yes whether it contains mutable or just immutables ones.
165 // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
166 // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848.
167 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
168 let mut result = None;
169 self.each_binding(|annotation, _, _, _| {
171 hir::BindingAnnotation::Ref => match result {
172 None | Some(hir::Mutability::Immutable) =>
173 result = Some(hir::Mutability::Immutable),
176 hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mutable),