]>
Commit | Line | Data |
---|---|---|
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 JJ |
11 | use middle::def::*; |
12 | use middle::ty; | |
13 | use util::nodemap::FnvHashMap; | |
223e47cc | 14 | |
1a4d82fc | 15 | use syntax::ast; |
c34b1796 | 16 | use syntax::ast_util::walk_pat; |
1a4d82fc | 17 | use syntax::codemap::{Span, DUMMY_SP}; |
223e47cc | 18 | |
1a4d82fc | 19 | pub type PatIdMap = FnvHashMap<ast::Ident, ast::NodeId>; |
223e47cc LB |
20 | |
21 | // This is used because same-named variables in alternative patterns need to | |
1a4d82fc JJ |
22 | // use the NodeId of their namesake in the first pattern. |
23 | pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap { | |
85aaf69f | 24 | let mut map = FnvHashMap(); |
1a4d82fc JJ |
25 | pat_bindings(dm, pat, |_bm, p_id, _s, path1| { |
26 | map.insert(path1.node, p_id); | |
27 | }); | |
223e47cc LB |
28 | map |
29 | } | |
30 | ||
1a4d82fc JJ |
31 | pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool { |
32 | match pat.node { | |
d9579d0f | 33 | ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true, |
1a4d82fc JJ |
34 | ast::PatEnum(_, _) | |
35 | ast::PatIdent(_, _, None) | | |
36 | ast::PatStruct(..) => { | |
c34b1796 AL |
37 | match dm.borrow().get(&pat.id).map(|d| d.full_def()) { |
38 | Some(DefVariant(..)) => true, | |
1a4d82fc JJ |
39 | _ => false |
40 | } | |
41 | } | |
42 | ast::PatVec(_, _, _) => true, | |
43 | _ => false | |
44 | } | |
45 | } | |
46 | ||
47 | pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool { | |
223e47cc | 48 | match pat.node { |
1a4d82fc JJ |
49 | ast::PatEnum(_, _) | |
50 | ast::PatIdent(_, _, None) | | |
51 | ast::PatStruct(..) => { | |
c34b1796 AL |
52 | match dm.borrow().get(&pat.id).map(|d| d.full_def()) { |
53 | Some(DefVariant(..)) | Some(DefStruct(..)) => true, | |
223e47cc LB |
54 | _ => false |
55 | } | |
56 | } | |
57 | _ => false | |
58 | } | |
59 | } | |
60 | ||
1a4d82fc | 61 | pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { |
223e47cc | 62 | match pat.node { |
d9579d0f | 63 | ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => { |
c34b1796 | 64 | match dm.borrow().get(&pat.id).map(|d| d.full_def()) { |
d9579d0f AL |
65 | Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, |
66 | _ => false | |
67 | } | |
68 | } | |
69 | _ => false | |
70 | } | |
71 | } | |
72 | ||
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 { | |
76 | match pat.node { | |
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) } | |
80 | else { None } ) { | |
81 | Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, | |
223e47cc LB |
82 | _ => false |
83 | } | |
84 | } | |
85 | _ => false | |
86 | } | |
87 | } | |
88 | ||
1a4d82fc | 89 | pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool { |
223e47cc | 90 | match pat.node { |
1a4d82fc | 91 | ast::PatIdent(..) => { |
223e47cc LB |
92 | !pat_is_variant_or_struct(dm, pat) && |
93 | !pat_is_const(dm, pat) | |
94 | } | |
95 | _ => false | |
96 | } | |
97 | } | |
98 | ||
1a4d82fc | 99 | pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool { |
223e47cc | 100 | match pat.node { |
1a4d82fc JJ |
101 | ast::PatIdent(..) => pat_is_binding(dm, pat), |
102 | ast::PatWild(_) => true, | |
223e47cc LB |
103 | _ => false |
104 | } | |
105 | } | |
106 | ||
1a4d82fc JJ |
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), | |
111 | { | |
112 | walk_pat(pat, |p| { | |
223e47cc | 113 | match p.node { |
1a4d82fc | 114 | ast::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => { |
223e47cc LB |
115 | it(binding_mode, p.id, p.span, pth); |
116 | } | |
117 | _ => {} | |
118 | } | |
1a4d82fc JJ |
119 | true |
120 | }); | |
121 | } | |
122 | ||
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; | |
127 | walk_pat(pat, |p| { | |
128 | if pat_is_binding(dm, p) { | |
129 | contains_bindings = true; | |
130 | false // there's at least one binding, can short circuit now. | |
131 | } else { | |
132 | true | |
133 | } | |
134 | }); | |
135 | contains_bindings | |
136 | } | |
137 | ||
c34b1796 AL |
138 | /// Checks if the pattern contains any `ref` or `ref mut` bindings. |
139 | pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> bool { | |
140 | let mut result = false; | |
141 | pat_bindings(dm, pat, |mode, _, _, _| { | |
142 | match mode { | |
143 | ast::BindingMode::BindByRef(_) => { result = true; } | |
144 | ast::BindingMode::BindByValue(_) => { } | |
145 | } | |
146 | }); | |
147 | result | |
148 | } | |
149 | ||
150 | /// Checks if the patterns for this arm contain any `ref` or `ref mut` | |
151 | /// bindings. | |
152 | pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> bool { | |
153 | arm.pats.iter().any(|pat| pat_contains_ref_binding(dm, pat)) | |
154 | } | |
155 | ||
156 | /// Checks if the pattern contains any patterns that bind something to | |
157 | /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`, | |
158 | pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool { | |
159 | let mut contains_bindings = false; | |
160 | walk_pat(pat, |p| { | |
161 | if pat_is_binding_or_wild(dm, p) { | |
162 | contains_bindings = true; | |
163 | false // there's at least one binding/wildcard, can short circuit now. | |
164 | } else { | |
165 | true | |
166 | } | |
167 | }); | |
168 | contains_bindings | |
169 | } | |
170 | ||
1a4d82fc JJ |
171 | pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> { |
172 | match pat.node { | |
173 | ast::PatIdent(ast::BindByValue(_), ref path1, None) => { | |
174 | Some(&path1.node) | |
175 | } | |
176 | _ => { | |
177 | None | |
178 | } | |
223e47cc LB |
179 | } |
180 | } | |
181 | ||
1a4d82fc JJ |
182 | pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path { |
183 | ty::with_path(tcx, id, |path| ast::Path { | |
184 | global: false, | |
185 | segments: path.last().map(|elem| ast::PathSegment { | |
186 | identifier: ast::Ident::new(elem.name()), | |
187 | parameters: ast::PathParameters::none(), | |
188 | }).into_iter().collect(), | |
189 | span: DUMMY_SP, | |
190 | }) | |
223e47cc | 191 | } |