]>
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; |
3157f602 | 13 | use rustc_data_structures::indexed_vec::Idx; |
54a0048b SL |
14 | use rustc_const_eval as const_eval; |
15 | use rustc::hir::def::Def; | |
5bcae85e | 16 | use rustc::hir::pat_util::EnumerateAndAdjustIterator; |
54a0048b | 17 | use rustc::ty::{self, Ty}; |
92a42be0 | 18 | use rustc::mir::repr::*; |
54a0048b | 19 | use rustc::hir::{self, PatKind}; |
b039eaaf | 20 | use syntax::ptr::P; |
3157f602 | 21 | use 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 |
36 | struct PatCx<'patcx, 'cx: 'patcx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { |
37 | cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>, | |
e9174d1e SL |
38 | } |
39 | ||
a7813a04 | 40 | impl<'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 | 52 | impl<'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 | } |