]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/pat_util.rs
Various minor/cosmetic improvements to code
[rust.git] / src / librustc / hir / pat_util.rs
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.
4 //
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.
10
11 use hir::def::Def;
12 use hir::def_id::DefId;
13 use hir::{self, HirId, PatKind};
14 use syntax::ast;
15 use syntax_pos::Span;
16
17 use std::iter::{Enumerate, ExactSizeIterator};
18
19 pub struct EnumerateAndAdjust<I> {
20     enumerate: Enumerate<I>,
21     gap_pos: usize,
22     gap_len: usize,
23 }
24
25 impl<I> Iterator for EnumerateAndAdjust<I> where I: Iterator {
26     type Item = (usize, <I as Iterator>::Item);
27
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)
31         })
32     }
33
34     fn size_hint(&self) -> (usize, Option<usize>) {
35         self.enumerate.size_hint()
36     }
37 }
38
39 pub trait EnumerateAndAdjustIterator {
40     fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option<usize>)
41         -> EnumerateAndAdjust<Self> where Self: Sized;
42 }
43
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();
48         EnumerateAndAdjust {
49             enumerate: self.enumerate(),
50             gap_pos: gap_pos.unwrap_or(expected_len),
51             gap_len: expected_len - actual_len,
52         }
53     }
54 }
55
56 impl hir::Pat {
57     pub fn is_refutable(&self) -> bool {
58         match self.node {
59             PatKind::Lit(_) |
60             PatKind::Range(..) |
61             PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
62             PatKind::Path(hir::QPath::TypeRelative(..)) => true,
63
64             PatKind::Path(hir::QPath::Resolved(_, ref path)) |
65             PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
66             PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
67                 match path.def {
68                     Def::Variant(..) | Def::VariantCtor(..) => true,
69                     _ => false
70                 }
71             }
72             PatKind::Slice(..) => true,
73             _ => false
74         }
75     }
76
77     pub fn is_const(&self) -> bool {
78         match self.node {
79             PatKind::Path(hir::QPath::TypeRelative(..)) => true,
80             PatKind::Path(hir::QPath::Resolved(_, ref path)) => {
81                 match path.def {
82                     Def::Const(..) | Def::AssociatedConst(..) => true,
83                     _ => false
84                 }
85             }
86             _ => false
87         }
88     }
89
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),
94     {
95         self.walk(|p| {
96             if let PatKind::Binding(binding_mode, _, ident, _) = p.node {
97                 f(binding_mode, p.hir_id, p.span, ident);
98             }
99             true
100         });
101     }
102
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;
107         self.walk(|p| {
108             if let PatKind::Binding(..) = p.node {
109                 contains_bindings = true;
110                 false // there's at least one binding, can short circuit now.
111             } else {
112                 true
113             }
114         });
115         contains_bindings
116     }
117
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;
122         self.walk(|p| {
123             match p.node {
124                 PatKind::Binding(..) | PatKind::Wild => {
125                     contains_bindings = true;
126                     false // there's at least one binding/wildcard, can short circuit now.
127                 }
128                 _ => true
129             }
130         });
131         contains_bindings
132     }
133
134     pub fn simple_ident(&self) -> Option<ast::Ident> {
135         match self.node {
136             PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) |
137             PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, None) => Some(ident),
138             _ => None,
139         }
140     }
141
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![];
145         self.walk(|p| {
146             match p.node {
147                 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
148                 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
149                 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
150                     match path.def {
151                         Def::Variant(id) |
152                         Def::VariantCtor(id, ..) => variants.push(id),
153                         _ => ()
154                     }
155                 }
156                 _ => ()
157             }
158             true
159         });
160         variants.sort();
161         variants.dedup();
162         variants
163     }
164
165     /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
166     /// yes whether it contains mutable or just immutables ones.
167     ///
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).
170     ///
171     /// See #44848.
172     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
173         let mut result = None;
174         self.each_binding(|annotation, _, _, _| {
175             match annotation {
176                 hir::BindingAnnotation::Ref => {
177                     match result {
178                         None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
179                         _ => (),
180                     }
181                 }
182                 hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
183                 _ => (),
184             }
185         });
186         result
187     }
188 }
189
190 impl hir::Arm {
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).
196         //
197         // See #44848.
198         self.pats.iter()
199                  .filter_map(|pat| pat.contains_explicit_ref_binding())
200                  .max_by_key(|m| match *m {
201                     hir::MutMutable => 1,
202                     hir::MutImmutable => 0,
203                  })
204     }
205 }