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};
16 use syntax::codemap::Spanned;
17 use syntax_pos::{Span, DUMMY_SP};
19 use std::iter::{Enumerate, ExactSizeIterator};
21 pub struct EnumerateAndAdjust<I> {
22 enumerate: Enumerate<I>,
27 impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
28 type Item = (usize, <I as Iterator>::Item);
30 fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
31 self.enumerate.next().map(|(i, elem)| {
32 (if i < self.gap_pos { i } else { i + self.gap_len }, elem)
37 pub trait EnumerateAndAdjustIterator {
38 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
39 -> EnumerateAndAdjust<Self> where Self: Sized;
42 impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
43 fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
44 -> EnumerateAndAdjust<Self> where Self: Sized {
45 let actual_len = self.len();
47 enumerate: self.enumerate(),
48 gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len },
49 gap_len: expected_len - actual_len,
54 pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
56 PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true,
57 PatKind::TupleStruct(..) |
59 PatKind::Struct(..) => {
60 match dm.get(&pat.id).map(|d| d.full_def()) {
61 Some(Def::Variant(..)) => true,
65 PatKind::Vec(..) => true,
70 pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
72 PatKind::Path(..) => {
73 match dm.get(&pat.id).map(|d| d.full_def()) {
74 Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
82 /// Call `f` on every "binding" in a pattern, e.g., on `a` in
83 /// `match foo() { Some(a) => (), None => () }`
84 pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)
85 where F: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
88 if let PatKind::Binding(binding_mode, ref pth, _) = p.node {
89 f(binding_mode, p.id, p.span, pth);
95 /// Checks if the pattern contains any patterns that bind something to
96 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
97 pub fn pat_contains_bindings(pat: &hir::Pat) -> bool {
98 let mut contains_bindings = false;
100 if let PatKind::Binding(..) = p.node {
101 contains_bindings = true;
102 false // there's at least one binding, can short circuit now.
110 /// Checks if the pattern contains any `ref` or `ref mut` bindings,
111 /// and if yes whether its containing mutable ones or just immutables ones.
112 pub fn pat_contains_ref_binding(pat: &hir::Pat) -> Option<hir::Mutability> {
113 let mut result = None;
114 pat_bindings(pat, |mode, _, _, _| {
115 if let hir::BindingMode::BindByRef(m) = mode {
116 // Pick Mutable as maximum
118 None | Some(hir::MutImmutable) => result = Some(m),
126 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
127 /// bindings, and if yes whether its containing mutable ones or just immutables ones.
128 pub fn arm_contains_ref_binding(arm: &hir::Arm) -> Option<hir::Mutability> {
130 .filter_map(|pat| pat_contains_ref_binding(pat))
131 .max_by_key(|m| match *m {
132 hir::MutMutable => 1,
133 hir::MutImmutable => 0,
137 /// Checks if the pattern contains any patterns that bind something to
138 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
139 pub fn pat_contains_bindings_or_wild(pat: &hir::Pat) -> bool {
140 let mut contains_bindings = false;
143 PatKind::Binding(..) | PatKind::Wild => {
144 contains_bindings = true;
145 false // there's at least one binding/wildcard, can short circuit now.
153 pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
155 PatKind::Binding(hir::BindByValue(..), ref path1, None) => {
164 pub fn def_to_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> hir::Path {
165 hir::Path::from_name(DUMMY_SP, tcx.item_name(id))
168 /// Return variants that are necessary to exist for the pattern to match.
169 pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
170 let mut variants = vec![];
173 PatKind::TupleStruct(..) |
175 PatKind::Struct(..) => {
176 match dm.get(&p.id) {
177 Some(&PathResolution { base_def: Def::Variant(id), .. }) => {