]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2015 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 hair::*; | |
92a42be0 | 12 | use hair::cx::Cx; |
e9174d1e | 13 | use rustc_data_structures::fnv::FnvHashMap; |
54a0048b SL |
14 | use rustc_const_eval as const_eval; |
15 | use rustc::hir::def::Def; | |
16 | use rustc::hir::pat_util::{pat_is_resolved_const, pat_is_binding}; | |
17 | use rustc::ty::{self, Ty}; | |
92a42be0 | 18 | use rustc::mir::repr::*; |
54a0048b | 19 | use rustc::hir::{self, PatKind}; |
b039eaaf | 20 | use syntax::ast; |
9cc50fc6 | 21 | use syntax::codemap::Span; |
b039eaaf | 22 | use syntax::ptr::P; |
e9174d1e SL |
23 | |
24 | /// When there are multiple patterns in a single arm, each one has its | |
25 | /// own node-ids for the bindings. References to the variables always | |
26 | /// use the node-ids from the first pattern in the arm, so we just | |
27 | /// remap the ids for all subsequent bindings to the first one. | |
28 | /// | |
29 | /// Example: | |
30 | /// ``` | |
31 | /// match foo { | |
32 | /// Test1(flavor /* def 1 */) | | |
33 | /// Test2(flavor /* def 2 */) if flavor /* ref 1 */.is_tasty() => { ... } | |
34 | /// _ => { ... } | |
35 | /// } | |
36 | /// ``` | |
92a42be0 SL |
37 | struct PatCx<'patcx, 'cx: 'patcx, 'tcx: 'cx> { |
38 | cx: &'patcx mut Cx<'cx, 'tcx>, | |
39 | binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>, | |
e9174d1e SL |
40 | } |
41 | ||
92a42be0 | 42 | impl<'cx, 'tcx> Cx<'cx, 'tcx> { |
9cc50fc6 SL |
43 | pub fn irrefutable_pat(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { |
44 | PatCx::new(self, None).to_pattern(pat) | |
e9174d1e SL |
45 | } |
46 | ||
92a42be0 SL |
47 | pub fn refutable_pat(&mut self, |
48 | binding_map: Option<&FnvHashMap<ast::Name, ast::NodeId>>, | |
9cc50fc6 | 49 | pat: &hir::Pat) |
92a42be0 | 50 | -> Pattern<'tcx> { |
9cc50fc6 | 51 | PatCx::new(self, binding_map).to_pattern(pat) |
e9174d1e | 52 | } |
92a42be0 | 53 | } |
e9174d1e | 54 | |
92a42be0 SL |
55 | impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> { |
56 | fn new(cx: &'patcx mut Cx<'cx, 'tcx>, | |
57 | binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>) | |
58 | -> PatCx<'patcx, 'cx, 'tcx> { | |
59 | PatCx { | |
60 | cx: cx, | |
61 | binding_map: binding_map, | |
e9174d1e SL |
62 | } |
63 | } | |
e9174d1e | 64 | |
9cc50fc6 | 65 | fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { |
54a0048b SL |
66 | let mut ty = self.cx.tcx.node_id_to_type(pat.id); |
67 | ||
92a42be0 | 68 | let kind = match pat.node { |
7453a54e | 69 | PatKind::Wild => PatternKind::Wild, |
e9174d1e | 70 | |
7453a54e | 71 | PatKind::Lit(ref value) => { |
92a42be0 | 72 | let value = const_eval::eval_const_expr(self.cx.tcx, value); |
b039eaaf SL |
73 | PatternKind::Constant { value: value } |
74 | } | |
e9174d1e | 75 | |
7453a54e | 76 | PatKind::Range(ref lo, ref hi) => { |
92a42be0 | 77 | let lo = const_eval::eval_const_expr(self.cx.tcx, lo); |
b039eaaf | 78 | let lo = Literal::Value { value: lo }; |
92a42be0 | 79 | let hi = const_eval::eval_const_expr(self.cx.tcx, hi); |
b039eaaf SL |
80 | let hi = Literal::Value { value: hi }; |
81 | PatternKind::Range { lo: lo, hi: hi } | |
82 | }, | |
e9174d1e | 83 | |
7453a54e | 84 | PatKind::Path(..) | PatKind::Ident(..) | PatKind::QPath(..) |
92a42be0 | 85 | if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) => |
e9174d1e | 86 | { |
92a42be0 | 87 | let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); |
e9174d1e | 88 | match def { |
54a0048b SL |
89 | Def::Const(def_id) | Def::AssociatedConst(def_id) => { |
90 | let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs); | |
91 | match const_eval::lookup_const_by_id(self.cx.tcx, def_id, substs) { | |
92 | Some((const_expr, _const_ty)) => { | |
93 | match const_eval::const_expr_to_pat(self.cx.tcx, | |
94 | const_expr, | |
95 | pat.id, | |
96 | pat.span) { | |
97 | Ok(pat) => | |
98 | return self.to_pattern(&pat), | |
99 | Err(_) => | |
100 | span_bug!( | |
101 | pat.span, "illegal constant"), | |
102 | } | |
b039eaaf SL |
103 | } |
104 | None => { | |
54a0048b | 105 | span_bug!( |
92a42be0 | 106 | pat.span, |
54a0048b SL |
107 | "cannot eval constant: {:?}", |
108 | def_id) | |
b039eaaf | 109 | } |
54a0048b SL |
110 | } |
111 | } | |
e9174d1e | 112 | _ => |
54a0048b | 113 | span_bug!( |
92a42be0 | 114 | pat.span, |
54a0048b SL |
115 | "def not a constant: {:?}", |
116 | def), | |
e9174d1e SL |
117 | } |
118 | } | |
119 | ||
7453a54e SL |
120 | PatKind::Ref(ref subpattern, _) | |
121 | PatKind::Box(ref subpattern) => { | |
9cc50fc6 | 122 | PatternKind::Deref { subpattern: self.to_pattern(subpattern) } |
e9174d1e SL |
123 | } |
124 | ||
7453a54e | 125 | PatKind::Vec(ref prefix, ref slice, ref suffix) => { |
92a42be0 | 126 | let ty = self.cx.tcx.node_id_to_type(pat.id); |
e9174d1e SL |
127 | match ty.sty { |
128 | ty::TyRef(_, mt) => | |
129 | PatternKind::Deref { | |
130 | subpattern: Pattern { | |
131 | ty: mt.ty, | |
92a42be0 | 132 | span: pat.span, |
9cc50fc6 | 133 | kind: Box::new(self.slice_or_array_pattern(pat.span, mt.ty, prefix, |
92a42be0 SL |
134 | slice, suffix)), |
135 | }, | |
e9174d1e SL |
136 | }, |
137 | ||
138 | ty::TySlice(..) | | |
139 | ty::TyArray(..) => | |
9cc50fc6 | 140 | self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), |
e9174d1e SL |
141 | |
142 | ref sty => | |
54a0048b | 143 | span_bug!( |
92a42be0 | 144 | pat.span, |
54a0048b SL |
145 | "unexpanded type for vector pattern: {:?}", |
146 | sty), | |
e9174d1e SL |
147 | } |
148 | } | |
149 | ||
7453a54e | 150 | PatKind::Tup(ref subpatterns) => { |
e9174d1e SL |
151 | let subpatterns = |
152 | subpatterns.iter() | |
153 | .enumerate() | |
92a42be0 SL |
154 | .map(|(i, subpattern)| FieldPattern { |
155 | field: Field::new(i), | |
9cc50fc6 | 156 | pattern: self.to_pattern(subpattern), |
e9174d1e SL |
157 | }) |
158 | .collect(); | |
159 | ||
160 | PatternKind::Leaf { subpatterns: subpatterns } | |
161 | } | |
162 | ||
7453a54e | 163 | PatKind::Ident(bm, ref ident, ref sub) |
92a42be0 | 164 | if pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) => |
e9174d1e SL |
165 | { |
166 | let id = match self.binding_map { | |
92a42be0 SL |
167 | None => pat.id, |
168 | Some(ref map) => map[&ident.node.name], | |
e9174d1e | 169 | }; |
92a42be0 | 170 | let var_ty = self.cx.tcx.node_id_to_type(pat.id); |
e9174d1e SL |
171 | let region = match var_ty.sty { |
172 | ty::TyRef(&r, _) => Some(r), | |
173 | _ => None, | |
174 | }; | |
175 | let (mutability, mode) = match bm { | |
176 | hir::BindByValue(hir::MutMutable) => | |
177 | (Mutability::Mut, BindingMode::ByValue), | |
178 | hir::BindByValue(hir::MutImmutable) => | |
179 | (Mutability::Not, BindingMode::ByValue), | |
180 | hir::BindByRef(hir::MutMutable) => | |
181 | (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)), | |
182 | hir::BindByRef(hir::MutImmutable) => | |
183 | (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)), | |
184 | }; | |
54a0048b SL |
185 | |
186 | // A ref x pattern is the same node used for x, and as such it has | |
187 | // x's type, which is &T, where we want T (the type being matched). | |
188 | if let hir::BindByRef(_) = bm { | |
189 | if let ty::TyRef(_, mt) = ty.sty { | |
190 | ty = mt.ty; | |
191 | } else { | |
192 | bug!("`ref {}` has wrong type {}", ident.node, ty); | |
193 | } | |
194 | } | |
195 | ||
e9174d1e SL |
196 | PatternKind::Binding { |
197 | mutability: mutability, | |
198 | mode: mode, | |
b039eaaf | 199 | name: ident.node.name, |
e9174d1e SL |
200 | var: id, |
201 | ty: var_ty, | |
9cc50fc6 | 202 | subpattern: self.to_opt_pattern(sub), |
e9174d1e SL |
203 | } |
204 | } | |
205 | ||
7453a54e | 206 | PatKind::Ident(..) | PatKind::Path(..) => { |
92a42be0 | 207 | self.variant_or_leaf(pat, vec![]) |
e9174d1e SL |
208 | } |
209 | ||
7453a54e | 210 | PatKind::TupleStruct(_, ref opt_subpatterns) => { |
e9174d1e SL |
211 | let subpatterns = |
212 | opt_subpatterns.iter() | |
213 | .flat_map(|v| v.iter()) | |
214 | .enumerate() | |
92a42be0 SL |
215 | .map(|(i, field)| FieldPattern { |
216 | field: Field::new(i), | |
9cc50fc6 | 217 | pattern: self.to_pattern(field), |
e9174d1e SL |
218 | }) |
219 | .collect(); | |
92a42be0 | 220 | self.variant_or_leaf(pat, subpatterns) |
e9174d1e SL |
221 | } |
222 | ||
7453a54e | 223 | PatKind::Struct(_, ref fields, _) => { |
92a42be0 SL |
224 | let pat_ty = self.cx.tcx.node_id_to_type(pat.id); |
225 | let adt_def = match pat_ty.sty { | |
226 | ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, | |
227 | _ => { | |
54a0048b | 228 | span_bug!( |
92a42be0 SL |
229 | pat.span, |
230 | "struct pattern not applied to struct or enum"); | |
231 | } | |
232 | }; | |
233 | ||
234 | let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); | |
235 | let variant_def = adt_def.variant_of_def(def); | |
236 | ||
e9174d1e SL |
237 | let subpatterns = |
238 | fields.iter() | |
92a42be0 SL |
239 | .map(|field| { |
240 | let index = variant_def.index_of_field_named(field.node.name); | |
241 | let index = index.unwrap_or_else(|| { | |
54a0048b | 242 | span_bug!( |
92a42be0 | 243 | pat.span, |
54a0048b SL |
244 | "no field with name {:?}", |
245 | field.node.name); | |
92a42be0 SL |
246 | }); |
247 | FieldPattern { | |
248 | field: Field::new(index), | |
9cc50fc6 | 249 | pattern: self.to_pattern(&field.node.pat), |
92a42be0 | 250 | } |
e9174d1e SL |
251 | }) |
252 | .collect(); | |
92a42be0 SL |
253 | |
254 | self.variant_or_leaf(pat, subpatterns) | |
e9174d1e SL |
255 | } |
256 | ||
7453a54e | 257 | PatKind::QPath(..) => { |
54a0048b | 258 | span_bug!(pat.span, "unexpanded macro or bad constant etc"); |
e9174d1e SL |
259 | } |
260 | }; | |
261 | ||
b039eaaf | 262 | Pattern { |
92a42be0 | 263 | span: pat.span, |
b039eaaf | 264 | ty: ty, |
92a42be0 SL |
265 | kind: Box::new(kind), |
266 | } | |
267 | } | |
268 | ||
9cc50fc6 SL |
269 | fn to_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> { |
270 | pats.iter().map(|p| self.to_pattern(p)).collect() | |
92a42be0 SL |
271 | } |
272 | ||
9cc50fc6 SL |
273 | fn to_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>> { |
274 | pat.as_ref().map(|p| self.to_pattern(p)) | |
92a42be0 SL |
275 | } |
276 | ||
277 | fn slice_or_array_pattern(&mut self, | |
9cc50fc6 | 278 | span: Span, |
92a42be0 | 279 | ty: Ty<'tcx>, |
9cc50fc6 SL |
280 | prefix: &[P<hir::Pat>], |
281 | slice: &Option<P<hir::Pat>>, | |
282 | suffix: &[P<hir::Pat>]) | |
92a42be0 SL |
283 | -> PatternKind<'tcx> { |
284 | match ty.sty { | |
285 | ty::TySlice(..) => { | |
286 | // matching a slice or fixed-length array | |
287 | PatternKind::Slice { | |
9cc50fc6 SL |
288 | prefix: self.to_patterns(prefix), |
289 | slice: self.to_opt_pattern(slice), | |
290 | suffix: self.to_patterns(suffix), | |
92a42be0 SL |
291 | } |
292 | } | |
293 | ||
294 | ty::TyArray(_, len) => { | |
295 | // fixed-length array | |
296 | assert!(len >= prefix.len() + suffix.len()); | |
297 | PatternKind::Array { | |
9cc50fc6 SL |
298 | prefix: self.to_patterns(prefix), |
299 | slice: self.to_opt_pattern(slice), | |
300 | suffix: self.to_patterns(suffix), | |
92a42be0 SL |
301 | } |
302 | } | |
303 | ||
304 | _ => { | |
54a0048b | 305 | span_bug!(span, "unexpanded macro or bad constant etc"); |
92a42be0 SL |
306 | } |
307 | } | |
308 | } | |
309 | ||
310 | fn variant_or_leaf(&mut self, | |
9cc50fc6 | 311 | pat: &hir::Pat, |
92a42be0 SL |
312 | subpatterns: Vec<FieldPattern<'tcx>>) |
313 | -> PatternKind<'tcx> { | |
314 | let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); | |
315 | match def { | |
7453a54e | 316 | Def::Variant(enum_id, variant_id) => { |
92a42be0 SL |
317 | let adt_def = self.cx.tcx.lookup_adt_def(enum_id); |
318 | if adt_def.variants.len() > 1 { | |
319 | PatternKind::Variant { | |
320 | adt_def: adt_def, | |
321 | variant_index: adt_def.variant_index_with_id(variant_id), | |
322 | subpatterns: subpatterns, | |
323 | } | |
324 | } else { | |
325 | PatternKind::Leaf { subpatterns: subpatterns } | |
326 | } | |
327 | } | |
328 | ||
7453a54e | 329 | Def::Struct(..) | Def::TyAlias(..) => { |
92a42be0 SL |
330 | PatternKind::Leaf { subpatterns: subpatterns } |
331 | } | |
332 | ||
333 | _ => { | |
54a0048b | 334 | span_bug!(pat.span, "inappropriate def for pattern: {:?}", def); |
92a42be0 | 335 | } |
b039eaaf | 336 | } |
e9174d1e SL |
337 | } |
338 | } |