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.
13 use util::nodemap::FnvHashMap;
16 use syntax::ast_util::walk_pat;
17 use syntax::codemap::{Span, DUMMY_SP};
19 pub type PatIdMap = FnvHashMap<ast::Ident, ast::NodeId>;
21 // This is used because same-named variables in alternative patterns need to
22 // use the NodeId of their namesake in the first pattern.
23 pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
24 let mut map = FnvHashMap();
25 pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
26 map.insert(path1.node, p_id);
31 pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
33 ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
35 ast::PatIdent(_, _, None) |
36 ast::PatStruct(..) => {
37 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
38 Some(DefVariant(..)) => true,
42 ast::PatVec(_, _, _) => true,
47 pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
50 ast::PatIdent(_, _, None) |
51 ast::PatStruct(..) => {
52 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
53 Some(DefVariant(..)) | Some(DefStruct(..)) => true,
61 pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
63 ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
64 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
65 Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
73 // Same as above, except that partially-resolved defs cause `false` to be
74 // returned instead of a panic.
75 pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
77 ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
78 match dm.borrow().get(&pat.id)
79 .and_then(|d| if d.depth == 0 { Some(d.base_def) }
81 Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
89 pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
91 ast::PatIdent(..) => {
92 !pat_is_variant_or_struct(dm, pat) &&
93 !pat_is_const(dm, pat)
99 pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
101 ast::PatIdent(..) => pat_is_binding(dm, pat),
102 ast::PatWild(_) => true,
107 /// Call `it` on every "binding" in a pattern, e.g., on `a` in
108 /// `match foo() { Some(a) => (), None => () }`
109 pub fn pat_bindings<I>(dm: &DefMap, pat: &ast::Pat, mut it: I) where
110 I: FnMut(ast::BindingMode, ast::NodeId, Span, &ast::SpannedIdent),
114 ast::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
115 it(binding_mode, p.id, p.span, pth);
123 /// Checks if the pattern contains any patterns that bind something to
124 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
125 pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool {
126 let mut contains_bindings = false;
128 if pat_is_binding(dm, p) {
129 contains_bindings = true;
130 false // there's at least one binding, can short circuit now.
138 /// Checks if the pattern contains any `ref` or `ref mut` bindings,
139 /// and if yes wether its containing mutable ones or just immutables ones.
140 pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> Option<ast::Mutability> {
141 let mut result = None;
142 pat_bindings(dm, pat, |mode, _, _, _| {
144 ast::BindingMode::BindByRef(m) => {
145 // Pick Mutable as maximum
147 None | Some(ast::MutImmutable) => result = Some(m),
151 ast::BindingMode::BindByValue(_) => { }
157 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
158 /// bindings, and if yes wether its containing mutable ones or just immutables ones.
159 pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> Option<ast::Mutability> {
161 .filter_map(|pat| pat_contains_ref_binding(dm, pat))
162 .max_by(|m| match *m {
163 ast::MutMutable => 1,
164 ast::MutImmutable => 0,
168 /// Checks if the pattern contains any patterns that bind something to
169 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
170 pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
171 let mut contains_bindings = false;
173 if pat_is_binding_or_wild(dm, p) {
174 contains_bindings = true;
175 false // there's at least one binding/wildcard, can short circuit now.
183 pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> {
185 ast::PatIdent(ast::BindByValue(_), ref path1, None) => {
194 pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path {
195 ty::with_path(tcx, id, |path| ast::Path {
197 segments: path.last().map(|elem| ast::PathSegment {
198 identifier: ast::Ident::new(elem.name()),
199 parameters: ast::PathParameters::none(),
200 }).into_iter().collect(),
205 /// Return variants that are necessary to exist for the pattern to match.
206 pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec<ast::NodeId> {
207 let mut variants = vec![];
211 ast::PatIdent(_, _, None) |
212 ast::PatStruct(..) => {
213 match dm.borrow().get(&p.id) {
214 Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
215 variants.push(id.node);