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