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, HirId, PatKind};
17 use std::iter::{Enumerate, ExactSizeIterator};
19 pub struct EnumerateAndAdjust<I> {
20 enumerate: Enumerate<I>,
25 impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
26 type Item = (usize, <I as Iterator>::Item);
28 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
29 self.enumerate.next().map(|(i, elem)| {
30 (if i < self.gap_pos { i } else { i + self.gap_len }, elem)
34 fn size_hint(&self) -> (usize, Option<usize>) {
35 self.enumerate.size_hint()
39 pub trait EnumerateAndAdjustIterator {
40 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
41 -> EnumerateAndAdjust<Self> where Self: Sized;
44 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
45 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
46 -> EnumerateAndAdjust<Self> where Self: Sized {
47 let actual_len = self.len();
49 enumerate: self.enumerate(),
50 gap_pos: gap_pos.unwrap_or(expected_len),
51 gap_len: expected_len - actual_len,
57 pub fn is_refutable(&self) -> bool {
61 PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
62 PatKind::Path(hir::QPath::TypeRelative(..)) => true,
64 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
65 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
66 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
68 Def::Variant(..) | Def::VariantCtor(..) => true,
72 PatKind::Slice(..) => true,
77 pub fn is_const(&self) -> bool {
79 PatKind::Path(hir::QPath::TypeRelative(..)) => true,
80 PatKind::Path(hir::QPath::Resolved(_, ref path)) => {
82 Def::Const(..) | Def::AssociatedConst(..) => true,
90 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
91 /// `match foo() { Some(a) => (), None => () }`
92 pub fn each_binding<F>(&self, mut f: F)
93 where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
96 if let PatKind::Binding(binding_mode, _, ident, _) = p.node {
97 f(binding_mode, p.hir_id, p.span, ident);
103 /// Checks if the pattern contains any patterns that bind something to
104 /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
105 pub fn contains_bindings(&self) -> bool {
106 let mut contains_bindings = false;
108 if let PatKind::Binding(..) = p.node {
109 contains_bindings = true;
110 false // there's at least one binding, can short circuit now.
118 /// Checks if the pattern contains any patterns that bind something to
119 /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
120 pub fn contains_bindings_or_wild(&self) -> bool {
121 let mut contains_bindings = false;
124 PatKind::Binding(..) | PatKind::Wild => {
125 contains_bindings = true;
126 false // there's at least one binding/wildcard, can short circuit now.
134 pub fn simple_ident(&self) -> Option<ast::Ident> {
136 PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) |
137 PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, None) => Some(ident),
142 /// Return variants that are necessary to exist for the pattern to match.
143 pub fn necessary_variants(&self) -> Vec<DefId> {
144 let mut variants = vec![];
147 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
148 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
149 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
152 Def::VariantCtor(id, ..) => variants.push(id),
165 /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
166 /// yes whether it contains mutable or just immutables ones.
168 /// FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
169 /// ref bindings are be implicit after #42640 (default match binding modes).
172 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
173 let mut result = None;
174 self.each_binding(|annotation, _, _, _| {
176 hir::BindingAnnotation::Ref => {
178 None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
182 hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
191 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
192 /// bindings, and if yes whether its containing mutable ones or just immutables ones.
193 pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
194 // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
195 // for #42640 (default match binding modes).
199 .filter_map(|pat| pat.contains_explicit_ref_binding())
200 .max_by_key(|m| match *m {
201 hir::MutMutable => 1,
202 hir::MutImmutable => 0,