]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/hair/cx/pattern.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / hair / cx / pattern.rs
CommitLineData
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
11use hair::*;
92a42be0 12use hair::cx::Cx;
e9174d1e 13use rustc_data_structures::fnv::FnvHashMap;
54a0048b
SL
14use rustc_const_eval as const_eval;
15use rustc::hir::def::Def;
16use rustc::hir::pat_util::{pat_is_resolved_const, pat_is_binding};
17use rustc::ty::{self, Ty};
92a42be0 18use rustc::mir::repr::*;
54a0048b 19use rustc::hir::{self, PatKind};
b039eaaf 20use syntax::ast;
9cc50fc6 21use syntax::codemap::Span;
b039eaaf 22use 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
37struct 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 42impl<'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
55impl<'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}