]> git.proxmox.com Git - rustc.git/blame - src/librustc_const_eval/pattern.rs
New upstream version 1.15.1+dfsg1
[rustc.git] / src / librustc_const_eval / pattern.rs
CommitLineData
c30ab7b3
SL
1// Copyright 2016 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 eval;
12
13use rustc::middle::const_val::ConstVal;
14use rustc::mir::{Field, BorrowKind, Mutability};
15use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
16use rustc::hir::{self, PatKind};
17use rustc::hir::def::Def;
18use rustc::hir::def_id::DefId;
19use rustc::hir::pat_util::EnumerateAndAdjustIterator;
20
21use rustc_data_structures::indexed_vec::Idx;
22
23use syntax::ast;
24use syntax::ptr::P;
25use syntax_pos::Span;
26
27#[derive(Clone, Debug)]
28pub enum PatternError {
29 StaticInPattern(Span),
30 BadConstInPattern(Span, DefId),
31 ConstEval(eval::ConstEvalErr),
32}
33
34#[derive(Copy, Clone, Debug)]
35pub enum BindingMode<'tcx> {
36 ByValue,
37 ByRef(&'tcx Region, BorrowKind),
38}
39
40#[derive(Clone, Debug)]
41pub struct FieldPattern<'tcx> {
42 pub field: Field,
43 pub pattern: Pattern<'tcx>,
44}
45
46#[derive(Clone, Debug)]
47pub struct Pattern<'tcx> {
48 pub ty: Ty<'tcx>,
49 pub span: Span,
50 pub kind: Box<PatternKind<'tcx>>,
51}
52
53#[derive(Clone, Debug)]
54pub enum PatternKind<'tcx> {
55 Wild,
56
57 /// x, ref x, x @ P, etc
58 Binding {
59 mutability: Mutability,
60 name: ast::Name,
61 mode: BindingMode<'tcx>,
62 var: ast::NodeId,
63 ty: Ty<'tcx>,
64 subpattern: Option<Pattern<'tcx>>,
65 },
66
67 /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
68 Variant {
476ff2be 69 adt_def: &'tcx AdtDef,
c30ab7b3
SL
70 variant_index: usize,
71 subpatterns: Vec<FieldPattern<'tcx>>,
72 },
73
74 /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
75 Leaf {
76 subpatterns: Vec<FieldPattern<'tcx>>,
77 },
78
79 /// box P, &P, &mut P, etc
80 Deref {
81 subpattern: Pattern<'tcx>,
82 },
83
84 Constant {
85 value: ConstVal,
86 },
87
88 Range {
89 lo: ConstVal,
90 hi: ConstVal,
91 },
92
93 /// matches against a slice, checking the length and extracting elements
94 Slice {
95 prefix: Vec<Pattern<'tcx>>,
96 slice: Option<Pattern<'tcx>>,
97 suffix: Vec<Pattern<'tcx>>,
98 },
99
100 /// fixed match against an array, irrefutable
101 Array {
102 prefix: Vec<Pattern<'tcx>>,
103 slice: Option<Pattern<'tcx>>,
104 suffix: Vec<Pattern<'tcx>>,
105 },
106}
107
108pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
109 pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
110 pub errors: Vec<PatternError>,
111}
112
113impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
114 pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &hir::Pat) -> Self {
115 let mut pcx = PatternContext::new(tcx);
116 let result = pcx.lower_pattern(pat);
117 if !pcx.errors.is_empty() {
118 span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
119 }
120 debug!("Pattern::from_hir({:?}) = {:?}", pat, result);
121 result
122 }
123}
124
125impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
126 pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
127 PatternContext { tcx: tcx, errors: vec![] }
128 }
129
130 pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
131 let mut ty = self.tcx.tables().node_id_to_type(pat.id);
132
133 let kind = match pat.node {
134 PatKind::Wild => PatternKind::Wild,
135
136 PatKind::Lit(ref value) => {
137 match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) {
138 Ok(value) => {
139 PatternKind::Constant { value: value }
140 }
141 Err(e) => {
142 self.errors.push(PatternError::ConstEval(e));
143 PatternKind::Wild
144 }
145 }
146 }
147
148 PatKind::Range(ref lo, ref hi) => {
149 let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo);
150 if let Err(ref e_lo) = r_lo {
151 self.errors.push(PatternError::ConstEval(e_lo.clone()));
152 }
153
154 let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi);
155 if let Err(ref e_hi) = r_hi {
156 self.errors.push(PatternError::ConstEval(e_hi.clone()));
157 }
158
159 if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) {
160 PatternKind::Range { lo: lo, hi: hi }
161 } else {
162 PatternKind::Wild
163 }
164 }
165
476ff2be
SL
166 PatKind::Path(ref qpath) => {
167 let def = self.tcx.tables().qpath_def(qpath, pat.id);
168 match def {
c30ab7b3
SL
169 Def::Const(def_id) | Def::AssociatedConst(def_id) => {
170 let tcx = self.tcx.global_tcx();
171 let substs = tcx.tables().node_id_item_substs(pat.id)
172 .unwrap_or_else(|| tcx.intern_substs(&[]));
173 match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
174 Some((const_expr, _const_ty)) => {
175 match eval::const_expr_to_pat(
176 tcx, const_expr, pat.id, pat.span)
177 {
178 Ok(pat) => return self.lower_pattern(&pat),
179 Err(_) => {
180 self.errors.push(PatternError::BadConstInPattern(
181 pat.span, def_id));
182 PatternKind::Wild
183 }
184 }
185 }
186 None => {
187 self.errors.push(PatternError::StaticInPattern(pat.span));
188 PatternKind::Wild
189 }
190 }
191 }
476ff2be 192 _ => self.lower_variant_or_leaf(def, vec![])
c30ab7b3
SL
193 }
194 }
195
196 PatKind::Ref(ref subpattern, _) |
197 PatKind::Box(ref subpattern) => {
198 PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
199 }
200
201 PatKind::Slice(ref prefix, ref slice, ref suffix) => {
202 let ty = self.tcx.tables().node_id_to_type(pat.id);
203 match ty.sty {
204 ty::TyRef(_, mt) =>
205 PatternKind::Deref {
206 subpattern: Pattern {
207 ty: mt.ty,
208 span: pat.span,
209 kind: Box::new(self.slice_or_array_pattern(
210 pat.span, mt.ty, prefix, slice, suffix))
211 },
212 },
213
214 ty::TySlice(..) |
215 ty::TyArray(..) =>
216 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
217
218 ref sty =>
219 span_bug!(
220 pat.span,
221 "unexpanded type for vector pattern: {:?}",
222 sty),
223 }
224 }
225
226 PatKind::Tuple(ref subpatterns, ddpos) => {
227 let ty = self.tcx.tables().node_id_to_type(pat.id);
228 match ty.sty {
229 ty::TyTuple(ref tys) => {
230 let subpatterns =
231 subpatterns.iter()
232 .enumerate_and_adjust(tys.len(), ddpos)
233 .map(|(i, subpattern)| FieldPattern {
234 field: Field::new(i),
235 pattern: self.lower_pattern(subpattern)
236 })
237 .collect();
238
239 PatternKind::Leaf { subpatterns: subpatterns }
240 }
241
242 ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
243 }
244 }
245
476ff2be 246 PatKind::Binding(bm, def_id, ref ident, ref sub) => {
c30ab7b3
SL
247 let id = self.tcx.map.as_local_node_id(def_id).unwrap();
248 let var_ty = self.tcx.tables().node_id_to_type(pat.id);
249 let region = match var_ty.sty {
250 ty::TyRef(r, _) => Some(r),
251 _ => None,
252 };
253 let (mutability, mode) = match bm {
254 hir::BindByValue(hir::MutMutable) =>
255 (Mutability::Mut, BindingMode::ByValue),
256 hir::BindByValue(hir::MutImmutable) =>
257 (Mutability::Not, BindingMode::ByValue),
258 hir::BindByRef(hir::MutMutable) =>
259 (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
260 hir::BindByRef(hir::MutImmutable) =>
261 (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
262 };
263
264 // A ref x pattern is the same node used for x, and as such it has
265 // x's type, which is &T, where we want T (the type being matched).
266 if let hir::BindByRef(_) = bm {
267 if let ty::TyRef(_, mt) = ty.sty {
268 ty = mt.ty;
269 } else {
270 bug!("`ref {}` has wrong type {}", ident.node, ty);
271 }
272 }
273
274 PatternKind::Binding {
275 mutability: mutability,
276 mode: mode,
277 name: ident.node,
278 var: id,
279 ty: var_ty,
280 subpattern: self.lower_opt_pattern(sub),
281 }
282 }
283
476ff2be
SL
284 PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
285 let def = self.tcx.tables().qpath_def(qpath, pat.id);
c30ab7b3
SL
286 let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
287 let adt_def = match pat_ty.sty {
288 ty::TyAdt(adt_def, _) => adt_def,
289 _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
290 };
476ff2be 291 let variant_def = adt_def.variant_of_def(def);
c30ab7b3
SL
292
293 let subpatterns =
294 subpatterns.iter()
295 .enumerate_and_adjust(variant_def.fields.len(), ddpos)
296 .map(|(i, field)| FieldPattern {
297 field: Field::new(i),
298 pattern: self.lower_pattern(field),
299 })
300 .collect();
476ff2be 301 self.lower_variant_or_leaf(def, subpatterns)
c30ab7b3
SL
302 }
303
476ff2be
SL
304 PatKind::Struct(ref qpath, ref fields, _) => {
305 let def = self.tcx.tables().qpath_def(qpath, pat.id);
c30ab7b3
SL
306 let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
307 let adt_def = match pat_ty.sty {
308 ty::TyAdt(adt_def, _) => adt_def,
309 _ => {
310 span_bug!(
311 pat.span,
312 "struct pattern not applied to an ADT");
313 }
314 };
476ff2be 315 let variant_def = adt_def.variant_of_def(def);
c30ab7b3
SL
316
317 let subpatterns =
318 fields.iter()
319 .map(|field| {
320 let index = variant_def.index_of_field_named(field.node.name);
321 let index = index.unwrap_or_else(|| {
322 span_bug!(
323 pat.span,
324 "no field with name {:?}",
325 field.node.name);
326 });
327 FieldPattern {
328 field: Field::new(index),
329 pattern: self.lower_pattern(&field.node.pat),
330 }
331 })
332 .collect();
333
476ff2be 334 self.lower_variant_or_leaf(def, subpatterns)
c30ab7b3
SL
335 }
336 };
337
338 Pattern {
339 span: pat.span,
340 ty: ty,
341 kind: Box::new(kind),
342 }
343 }
344
345 fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
346 pats.iter().map(|p| self.lower_pattern(p)).collect()
347 }
348
349 fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
350 {
351 pat.as_ref().map(|p| self.lower_pattern(p))
352 }
353
354 fn flatten_nested_slice_patterns(
355 &mut self,
356 prefix: Vec<Pattern<'tcx>>,
357 slice: Option<Pattern<'tcx>>,
358 suffix: Vec<Pattern<'tcx>>)
359 -> (Vec<Pattern<'tcx>>, Option<Pattern<'tcx>>, Vec<Pattern<'tcx>>)
360 {
361 let orig_slice = match slice {
362 Some(orig_slice) => orig_slice,
363 None => return (prefix, slice, suffix)
364 };
365 let orig_prefix = prefix;
366 let orig_suffix = suffix;
367
368 // dance because of intentional borrow-checker stupidity.
369 let kind = *orig_slice.kind;
370 match kind {
371 PatternKind::Slice { prefix, slice, mut suffix } |
372 PatternKind::Array { prefix, slice, mut suffix } => {
373 let mut orig_prefix = orig_prefix;
374
375 orig_prefix.extend(prefix);
376 suffix.extend(orig_suffix);
377
378 (orig_prefix, slice, suffix)
379 }
380 _ => {
381 (orig_prefix, Some(Pattern {
382 kind: box kind, ..orig_slice
383 }), orig_suffix)
384 }
385 }
386 }
387
388 fn slice_or_array_pattern(
389 &mut self,
390 span: Span,
391 ty: Ty<'tcx>,
392 prefix: &[P<hir::Pat>],
393 slice: &Option<P<hir::Pat>>,
394 suffix: &[P<hir::Pat>])
395 -> PatternKind<'tcx>
396 {
397 let prefix = self.lower_patterns(prefix);
398 let slice = self.lower_opt_pattern(slice);
399 let suffix = self.lower_patterns(suffix);
400 let (prefix, slice, suffix) =
401 self.flatten_nested_slice_patterns(prefix, slice, suffix);
402
403 match ty.sty {
404 ty::TySlice(..) => {
405 // matching a slice or fixed-length array
406 PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
407 }
408
409 ty::TyArray(_, len) => {
410 // fixed-length array
411 assert!(len >= prefix.len() + suffix.len());
412 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
413 }
414
415 _ => {
416 span_bug!(span, "bad slice pattern type {:?}", ty);
417 }
418 }
419 }
420
421 fn lower_variant_or_leaf(
422 &mut self,
476ff2be 423 def: Def,
c30ab7b3
SL
424 subpatterns: Vec<FieldPattern<'tcx>>)
425 -> PatternKind<'tcx>
426 {
476ff2be 427 match def {
c30ab7b3
SL
428 Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
429 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
430 let adt_def = self.tcx.lookup_adt_def(enum_id);
431 if adt_def.variants.len() > 1 {
432 PatternKind::Variant {
433 adt_def: adt_def,
434 variant_index: adt_def.variant_index_with_id(variant_id),
435 subpatterns: subpatterns,
436 }
437 } else {
438 PatternKind::Leaf { subpatterns: subpatterns }
439 }
440 }
441
442 Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
443 Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
444 PatternKind::Leaf { subpatterns: subpatterns }
445 }
446
476ff2be 447 _ => bug!()
c30ab7b3
SL
448 }
449 }
450}
451
452pub trait PatternFoldable<'tcx> : Sized {
453 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
454 self.super_fold_with(folder)
455 }
456
457 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
458}
459
460pub trait PatternFolder<'tcx> : Sized {
461 fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
462 pattern.super_fold_with(self)
463 }
464
465 fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
466 kind.super_fold_with(self)
467 }
468}
469
470
471impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
472 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
473 let content: T = (**self).fold_with(folder);
474 box content
475 }
476}
477
478impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
479 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
480 self.iter().map(|t| t.fold_with(folder)).collect()
481 }
482}
483
484impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
485 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
486 self.as_ref().map(|t| t.fold_with(folder))
487 }
488}
489
476ff2be
SL
490macro_rules! CloneImpls {
491 (<$lt_tcx:tt> $($ty:ty),+) => {
c30ab7b3 492 $(
476ff2be
SL
493 impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
494 fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
495 Clone::clone(self)
c30ab7b3
SL
496 }
497 }
498 )+
499 }
500}
501
476ff2be
SL
502CloneImpls!{ <'tcx>
503 Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal,
504 Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef
505}
c30ab7b3
SL
506
507impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
508 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
509 FieldPattern {
510 field: self.field.fold_with(folder),
511 pattern: self.pattern.fold_with(folder)
512 }
513 }
514}
515
516impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
517 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
518 folder.fold_pattern(self)
519 }
520
521 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
522 Pattern {
523 ty: self.ty.fold_with(folder),
524 span: self.span.fold_with(folder),
525 kind: self.kind.fold_with(folder)
526 }
527 }
528}
529
530impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
531 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
532 folder.fold_pattern_kind(self)
533 }
534
535 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
536 match *self {
537 PatternKind::Wild => PatternKind::Wild,
538 PatternKind::Binding {
539 mutability,
540 name,
541 mode,
542 var,
543 ty,
544 ref subpattern,
545 } => PatternKind::Binding {
546 mutability: mutability.fold_with(folder),
547 name: name.fold_with(folder),
548 mode: mode.fold_with(folder),
549 var: var.fold_with(folder),
550 ty: ty.fold_with(folder),
551 subpattern: subpattern.fold_with(folder),
552 },
553 PatternKind::Variant {
554 adt_def,
555 variant_index,
556 ref subpatterns,
557 } => PatternKind::Variant {
558 adt_def: adt_def.fold_with(folder),
559 variant_index: variant_index.fold_with(folder),
560 subpatterns: subpatterns.fold_with(folder)
561 },
562 PatternKind::Leaf {
563 ref subpatterns,
564 } => PatternKind::Leaf {
565 subpatterns: subpatterns.fold_with(folder),
566 },
567 PatternKind::Deref {
568 ref subpattern,
569 } => PatternKind::Deref {
570 subpattern: subpattern.fold_with(folder),
571 },
572 PatternKind::Constant {
573 ref value
574 } => PatternKind::Constant {
575 value: value.fold_with(folder)
576 },
577 PatternKind::Range {
578 ref lo,
579 ref hi
580 } => PatternKind::Range {
581 lo: lo.fold_with(folder),
582 hi: hi.fold_with(folder)
583 },
584 PatternKind::Slice {
585 ref prefix,
586 ref slice,
587 ref suffix,
588 } => PatternKind::Slice {
589 prefix: prefix.fold_with(folder),
590 slice: slice.fold_with(folder),
591 suffix: suffix.fold_with(folder)
592 },
593 PatternKind::Array {
594 ref prefix,
595 ref slice,
596 ref suffix
597 } => PatternKind::Array {
598 prefix: prefix.fold_with(folder),
599 slice: slice.fold_with(folder),
600 suffix: suffix.fold_with(folder)
601 },
602 }
603 }
604}