1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use hir::def_id::DefId;
13 use hir::{self, PatKind};
15 use syntax::codemap::Spanned;
18 use std::iter::{Enumerate, ExactSizeIterator};
20 pub struct EnumerateAndAdjust<I> {
21 enumerate: Enumerate<I>,
26 impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
27 type Item = (usize, <I as Iterator>::Item);
29 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
30 self.enumerate.next().map(|(i, elem)| {
31 (if i < self.gap_pos { i } else { i + self.gap_len }, elem)
36 pub trait EnumerateAndAdjustIterator {
37 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
38 -> EnumerateAndAdjust<Self> where Self: Sized;
41 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
42 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
43 -> EnumerateAndAdjust<Self> where Self: Sized {
44 let actual_len = self.len();
46 enumerate: self.enumerate(),
47 gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
48 gap_len: expected_len - actual_len,
54 pub fn is_refutable(&self) -> bool {
58 PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
59 PatKind::Path(hir::QPath::TypeRelative(..)) => true,
61 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
62 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
63 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
65 Def::Variant(..) | Def::VariantCtor(..) => true,
69 PatKind::Slice(..) => true,
74 pub fn is_const(&self) -> bool {
76 PatKind::Path(hir::QPath::TypeRelative(..)) => true,
77 PatKind::Path(hir::QPath::Resolved(_, ref path)) => {
79 Def::Const(..) | Def::AssociatedConst(..) => true,
87 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
88 /// `match foo() { Some(a) => (), None => () }`
89 pub fn each_binding<F>(&self, mut f: F)
90 where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned<ast::Name>),
93 if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
94 f(binding_mode, p.id, p.span, pth);
100 /// Checks if the pattern contains any patterns that bind something to
101 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
102 pub fn contains_bindings(&self) -> bool {
103 let mut contains_bindings = false;
105 if let PatKind::Binding(..) = p.node {
106 contains_bindings = true;
107 false // there's at least one binding, can short circuit now.
115 /// Checks if the pattern contains any patterns that bind something to
116 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
117 pub fn contains_bindings_or_wild(&self) -> bool {
118 let mut contains_bindings = false;
121 PatKind::Binding(..) | PatKind::Wild => {
122 contains_bindings = true;
123 false // there's at least one binding/wildcard, can short circuit now.
131 pub fn simple_name(&self) -> Option<ast::Name> {
133 PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
134 PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
140 /// Return variants that are necessary to exist for the pattern to match.
141 pub fn necessary_variants(&self) -> Vec<DefId> {
142 let mut variants = vec![];
145 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
146 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
147 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
150 Def::VariantCtor(id, ..) => variants.push(id),
163 /// Checks if the pattern contains any `ref` or `ref mut` bindings,
164 /// and if yes whether it contains mutable or just immutables ones.
166 /// FIXME(tschottdorf): this is problematic as the HIR is being scraped,
167 /// but ref bindings may be implicit after #42640.
168 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
169 let mut result = None;
170 self.each_binding(|annotation, _, _, _| {
172 hir::BindingAnnotation::Ref => {
174 None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
178 hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
187 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
188 /// bindings, and if yes whether its containing mutable ones or just immutables ones.
189 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
190 // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
193 .filter_map(|pat| pat.contains_explicit_ref_binding())
194 .max_by_key(|m| match *m {
195 hir::MutMutable => 1,
196 hir::MutImmutable => 0,