]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/pat_util.rs
Imported Upstream version 1.4.0+dfsg1
[rustc.git] / src / librustc / middle / pat_util.rs
CommitLineData
223e47cc
LB
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
1a4d82fc 11use middle::def::*;
e9174d1e 12use middle::def_id::DefId;
1a4d82fc
JJ
13use middle::ty;
14use util::nodemap::FnvHashMap;
223e47cc 15
1a4d82fc 16use syntax::ast;
e9174d1e
SL
17use rustc_front::hir;
18use rustc_front::util::walk_pat;
1a4d82fc 19use syntax::codemap::{Span, DUMMY_SP};
223e47cc 20
1a4d82fc 21pub type PatIdMap = FnvHashMap<ast::Ident, ast::NodeId>;
223e47cc
LB
22
23// This is used because same-named variables in alternative patterns need to
1a4d82fc 24// use the NodeId of their namesake in the first pattern.
e9174d1e 25pub fn pat_id_map(dm: &DefMap, pat: &hir::Pat) -> PatIdMap {
85aaf69f 26 let mut map = FnvHashMap();
1a4d82fc
JJ
27 pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
28 map.insert(path1.node, p_id);
29 });
223e47cc
LB
30 map
31}
32
e9174d1e 33pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
1a4d82fc 34 match pat.node {
e9174d1e
SL
35 hir::PatLit(_) | hir::PatRange(_, _) | hir::PatQPath(..) => true,
36 hir::PatEnum(_, _) |
37 hir::PatIdent(_, _, None) |
38 hir::PatStruct(..) => {
c34b1796
AL
39 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
40 Some(DefVariant(..)) => true,
1a4d82fc
JJ
41 _ => false
42 }
43 }
e9174d1e 44 hir::PatVec(_, _, _) => true,
1a4d82fc
JJ
45 _ => false
46 }
47}
48
e9174d1e 49pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool {
223e47cc 50 match pat.node {
e9174d1e
SL
51 hir::PatEnum(_, _) |
52 hir::PatIdent(_, _, None) |
53 hir::PatStruct(..) => {
c34b1796
AL
54 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
55 Some(DefVariant(..)) | Some(DefStruct(..)) => true,
223e47cc
LB
56 _ => false
57 }
58 }
59 _ => false
60 }
61}
62
e9174d1e 63pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
223e47cc 64 match pat.node {
e9174d1e 65 hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => {
c34b1796 66 match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
d9579d0f
AL
67 Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
68 _ => false
69 }
70 }
71 _ => false
72 }
73}
74
75// Same as above, except that partially-resolved defs cause `false` to be
76// returned instead of a panic.
e9174d1e 77pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
d9579d0f 78 match pat.node {
e9174d1e 79 hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => {
d9579d0f
AL
80 match dm.borrow().get(&pat.id)
81 .and_then(|d| if d.depth == 0 { Some(d.base_def) }
82 else { None } ) {
83 Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
223e47cc
LB
84 _ => false
85 }
86 }
87 _ => false
88 }
89}
90
e9174d1e 91pub fn pat_is_binding(dm: &DefMap, pat: &hir::Pat) -> bool {
223e47cc 92 match pat.node {
e9174d1e 93 hir::PatIdent(..) => {
223e47cc
LB
94 !pat_is_variant_or_struct(dm, pat) &&
95 !pat_is_const(dm, pat)
96 }
97 _ => false
98 }
99}
100
e9174d1e 101pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
223e47cc 102 match pat.node {
e9174d1e
SL
103 hir::PatIdent(..) => pat_is_binding(dm, pat),
104 hir::PatWild(_) => true,
223e47cc
LB
105 _ => false
106 }
107}
108
1a4d82fc
JJ
109/// Call `it` on every "binding" in a pattern, e.g., on `a` in
110/// `match foo() { Some(a) => (), None => () }`
e9174d1e
SL
111pub fn pat_bindings<I>(dm: &DefMap, pat: &hir::Pat, mut it: I) where
112 I: FnMut(hir::BindingMode, ast::NodeId, Span, &hir::SpannedIdent),
1a4d82fc
JJ
113{
114 walk_pat(pat, |p| {
223e47cc 115 match p.node {
e9174d1e 116 hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
223e47cc
LB
117 it(binding_mode, p.id, p.span, pth);
118 }
119 _ => {}
120 }
1a4d82fc
JJ
121 true
122 });
123}
124
125/// Checks if the pattern contains any patterns that bind something to
126/// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
e9174d1e 127pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool {
1a4d82fc
JJ
128 let mut contains_bindings = false;
129 walk_pat(pat, |p| {
130 if pat_is_binding(dm, p) {
131 contains_bindings = true;
132 false // there's at least one binding, can short circuit now.
133 } else {
134 true
135 }
136 });
137 contains_bindings
138}
139
62682a34
SL
140/// Checks if the pattern contains any `ref` or `ref mut` bindings,
141/// and if yes wether its containing mutable ones or just immutables ones.
e9174d1e 142pub fn pat_contains_ref_binding(dm: &DefMap, pat: &hir::Pat) -> Option<hir::Mutability> {
62682a34 143 let mut result = None;
c34b1796
AL
144 pat_bindings(dm, pat, |mode, _, _, _| {
145 match mode {
e9174d1e 146 hir::BindingMode::BindByRef(m) => {
62682a34
SL
147 // Pick Mutable as maximum
148 match result {
e9174d1e 149 None | Some(hir::MutImmutable) => result = Some(m),
62682a34
SL
150 _ => (),
151 }
152 }
e9174d1e 153 hir::BindingMode::BindByValue(_) => { }
c34b1796
AL
154 }
155 });
156 result
157}
158
159/// Checks if the patterns for this arm contain any `ref` or `ref mut`
62682a34 160/// bindings, and if yes wether its containing mutable ones or just immutables ones.
e9174d1e 161pub fn arm_contains_ref_binding(dm: &DefMap, arm: &hir::Arm) -> Option<hir::Mutability> {
62682a34
SL
162 arm.pats.iter()
163 .filter_map(|pat| pat_contains_ref_binding(dm, pat))
164 .max_by(|m| match *m {
e9174d1e
SL
165 hir::MutMutable => 1,
166 hir::MutImmutable => 0,
62682a34 167 })
c34b1796
AL
168}
169
170/// Checks if the pattern contains any patterns that bind something to
171/// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
e9174d1e 172pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
c34b1796
AL
173 let mut contains_bindings = false;
174 walk_pat(pat, |p| {
175 if pat_is_binding_or_wild(dm, p) {
176 contains_bindings = true;
177 false // there's at least one binding/wildcard, can short circuit now.
178 } else {
179 true
180 }
181 });
182 contains_bindings
183}
184
e9174d1e 185pub fn simple_identifier<'a>(pat: &'a hir::Pat) -> Option<&'a ast::Ident> {
1a4d82fc 186 match pat.node {
e9174d1e 187 hir::PatIdent(hir::BindByValue(_), ref path1, None) => {
1a4d82fc
JJ
188 Some(&path1.node)
189 }
190 _ => {
191 None
192 }
223e47cc
LB
193 }
194}
195
e9174d1e
SL
196pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path {
197 tcx.with_path(id, |path| hir::Path {
1a4d82fc 198 global: false,
e9174d1e 199 segments: path.last().map(|elem| hir::PathSegment {
1a4d82fc 200 identifier: ast::Ident::new(elem.name()),
e9174d1e 201 parameters: hir::PathParameters::none(),
1a4d82fc
JJ
202 }).into_iter().collect(),
203 span: DUMMY_SP,
204 })
223e47cc 205}
62682a34
SL
206
207/// Return variants that are necessary to exist for the pattern to match.
e9174d1e 208pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<ast::NodeId> {
62682a34
SL
209 let mut variants = vec![];
210 walk_pat(pat, |p| {
211 match p.node {
e9174d1e
SL
212 hir::PatEnum(_, _) |
213 hir::PatIdent(_, _, None) |
214 hir::PatStruct(..) => {
62682a34
SL
215 match dm.borrow().get(&p.id) {
216 Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
217 variants.push(id.node);
218 }
219 _ => ()
220 }
221 }
222 _ => ()
223 }
224 true
225 });
226 variants.sort();
227 variants.dedup();
228 variants
229}