]> git.lizzy.rs Git - rust.git/blob - src/librustc_const_eval/pattern.rs
Auto merge of #43298 - gaurikholkar:lifetime_errors, r=estebank
[rust.git] / src / librustc_const_eval / pattern.rs
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
11 use eval;
12
13 use rustc::middle::const_val::{ConstEvalErr, ConstVal};
14 use rustc::mir::{Field, BorrowKind, Mutability};
15 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
16 use rustc::ty::subst::{Substs, Kind};
17 use rustc::hir::{self, PatKind, RangeEnd};
18 use rustc::hir::def::{Def, CtorKind};
19 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
20
21 use rustc_data_structures::indexed_vec::Idx;
22
23 use std::fmt;
24 use syntax::ast;
25 use syntax::ptr::P;
26 use syntax_pos::Span;
27
28 #[derive(Clone, Debug)]
29 pub enum PatternError<'tcx> {
30     StaticInPattern(Span),
31     ConstEval(ConstEvalErr<'tcx>),
32 }
33
34 #[derive(Copy, Clone, Debug)]
35 pub enum BindingMode<'tcx> {
36     ByValue,
37     ByRef(Region<'tcx>, BorrowKind),
38 }
39
40 #[derive(Clone, Debug)]
41 pub struct FieldPattern<'tcx> {
42     pub field: Field,
43     pub pattern: Pattern<'tcx>,
44 }
45
46 #[derive(Clone, Debug)]
47 pub struct Pattern<'tcx> {
48     pub ty: Ty<'tcx>,
49     pub span: Span,
50     pub kind: Box<PatternKind<'tcx>>,
51 }
52
53 #[derive(Clone, Debug)]
54 pub 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 {
69         adt_def: &'tcx AdtDef,
70         substs: &'tcx Substs<'tcx>,
71         variant_index: usize,
72         subpatterns: Vec<FieldPattern<'tcx>>,
73     },
74
75     /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
76     Leaf {
77         subpatterns: Vec<FieldPattern<'tcx>>,
78     },
79
80     /// box P, &P, &mut P, etc
81     Deref {
82         subpattern: Pattern<'tcx>,
83     },
84
85     Constant {
86         value: ConstVal<'tcx>,
87     },
88
89     Range {
90         lo: ConstVal<'tcx>,
91         hi: ConstVal<'tcx>,
92         end: RangeEnd,
93     },
94
95     /// matches against a slice, checking the length and extracting elements
96     Slice {
97         prefix: Vec<Pattern<'tcx>>,
98         slice: Option<Pattern<'tcx>>,
99         suffix: Vec<Pattern<'tcx>>,
100     },
101
102     /// fixed match against an array, irrefutable
103     Array {
104         prefix: Vec<Pattern<'tcx>>,
105         slice: Option<Pattern<'tcx>>,
106         suffix: Vec<Pattern<'tcx>>,
107     },
108 }
109
110 fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
111     match *value {
112         ConstVal::Float(ref x) => write!(f, "{}", x),
113         ConstVal::Integral(ref i) => write!(f, "{}", i),
114         ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
115         ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
116         ConstVal::Bool(b) => write!(f, "{:?}", b),
117         ConstVal::Char(c) => write!(f, "{:?}", c),
118         ConstVal::Variant(_) |
119         ConstVal::Struct(_) |
120         ConstVal::Tuple(_) |
121         ConstVal::Function(..) |
122         ConstVal::Array(..) |
123         ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
124     }
125 }
126
127 impl<'tcx> fmt::Display for Pattern<'tcx> {
128     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129         match *self.kind {
130             PatternKind::Wild => write!(f, "_"),
131             PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
132                 let is_mut = match mode {
133                     BindingMode::ByValue => mutability == Mutability::Mut,
134                     BindingMode::ByRef(_, bk) => {
135                         write!(f, "ref ")?;
136                         bk == BorrowKind::Mut
137                     }
138                 };
139                 if is_mut {
140                     write!(f, "mut ")?;
141                 }
142                 write!(f, "{}", name)?;
143                 if let Some(ref subpattern) = *subpattern {
144                     write!(f, " @ {}", subpattern)?;
145                 }
146                 Ok(())
147             }
148             PatternKind::Variant { ref subpatterns, .. } |
149             PatternKind::Leaf { ref subpatterns } => {
150                 let variant = match *self.kind {
151                     PatternKind::Variant { adt_def, variant_index, .. } => {
152                         Some(&adt_def.variants[variant_index])
153                     }
154                     _ => if let ty::TyAdt(adt, _) = self.ty.sty {
155                         if adt.is_univariant() {
156                             Some(&adt.variants[0])
157                         } else {
158                             None
159                         }
160                     } else {
161                         None
162                     }
163                 };
164
165                 let mut first = true;
166                 let mut start_or_continue = || if first { first = false; "" } else { ", " };
167
168                 if let Some(variant) = variant {
169                     write!(f, "{}", variant.name)?;
170
171                     // Only for TyAdt we can have `S {...}`,
172                     // which we handle separately here.
173                     if variant.ctor_kind == CtorKind::Fictive {
174                         write!(f, " {{ ")?;
175
176                         let mut printed = 0;
177                         for p in subpatterns {
178                             if let PatternKind::Wild = *p.pattern.kind {
179                                 continue;
180                             }
181                             let name = variant.fields[p.field.index()].name;
182                             write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
183                             printed += 1;
184                         }
185
186                         if printed < variant.fields.len() {
187                             write!(f, "{}..", start_or_continue())?;
188                         }
189
190                         return write!(f, " }}");
191                     }
192                 }
193
194                 let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
195                 if num_fields != 0 || variant.is_none() {
196                     write!(f, "(")?;
197                     for i in 0..num_fields {
198                         write!(f, "{}", start_or_continue())?;
199
200                         // Common case: the field is where we expect it.
201                         if let Some(p) = subpatterns.get(i) {
202                             if p.field.index() == i {
203                                 write!(f, "{}", p.pattern)?;
204                                 continue;
205                             }
206                         }
207
208                         // Otherwise, we have to go looking for it.
209                         if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
210                             write!(f, "{}", p.pattern)?;
211                         } else {
212                             write!(f, "_")?;
213                         }
214                     }
215                     write!(f, ")")?;
216                 }
217
218                 Ok(())
219             }
220             PatternKind::Deref { ref subpattern } => {
221                 match self.ty.sty {
222                     ty::TyAdt(def, _) if def.is_box() => write!(f, "box ")?,
223                     ty::TyRef(_, mt) => {
224                         write!(f, "&")?;
225                         if mt.mutbl == hir::MutMutable {
226                             write!(f, "mut ")?;
227                         }
228                     }
229                     _ => bug!("{} is a bad Deref pattern type", self.ty)
230                 }
231                 write!(f, "{}", subpattern)
232             }
233             PatternKind::Constant { ref value } => {
234                 print_const_val(value, f)
235             }
236             PatternKind::Range { ref lo, ref hi, ref end } => {
237                 print_const_val(lo, f)?;
238                 match *end {
239                     RangeEnd::Included => write!(f, "...")?,
240                     RangeEnd::Excluded => write!(f, "..")?,
241                 }
242                 print_const_val(hi, f)
243             }
244             PatternKind::Slice { ref prefix, ref slice, ref suffix } |
245             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
246                 let mut first = true;
247                 let mut start_or_continue = || if first { first = false; "" } else { ", " };
248                 write!(f, "[")?;
249                 for p in prefix {
250                     write!(f, "{}{}", start_or_continue(), p)?;
251                 }
252                 if let Some(ref slice) = *slice {
253                     write!(f, "{}", start_or_continue())?;
254                     match *slice.kind {
255                         PatternKind::Wild => {}
256                         _ => write!(f, "{}", slice)?
257                     }
258                     write!(f, "..")?;
259                 }
260                 for p in suffix {
261                     write!(f, "{}{}", start_or_continue(), p)?;
262                 }
263                 write!(f, "]")
264             }
265         }
266     }
267 }
268
269 pub struct PatternContext<'a, 'tcx: 'a> {
270     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
271     pub param_env: ty::ParamEnv<'tcx>,
272     pub tables: &'a ty::TypeckTables<'tcx>,
273     pub substs: &'tcx Substs<'tcx>,
274     pub errors: Vec<PatternError<'tcx>>,
275 }
276
277 impl<'a, 'tcx> Pattern<'tcx> {
278     pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
279                     param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
280                     tables: &'a ty::TypeckTables<'tcx>,
281                     pat: &hir::Pat) -> Self {
282         let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
283         let result = pcx.lower_pattern(pat);
284         if !pcx.errors.is_empty() {
285             span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
286         }
287         debug!("Pattern::from_hir({:?}) = {:?}", pat, result);
288         result
289     }
290 }
291
292 impl<'a, 'tcx> PatternContext<'a, 'tcx> {
293     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
294                param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
295                tables: &'a ty::TypeckTables<'tcx>) -> Self {
296         PatternContext {
297             tcx,
298             param_env: param_env_and_substs.param_env,
299             tables,
300             substs: param_env_and_substs.value,
301             errors: vec![]
302         }
303     }
304
305     pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
306         let mut ty = self.tables.node_id_to_type(pat.id);
307
308         let kind = match pat.node {
309             PatKind::Wild => PatternKind::Wild,
310
311             PatKind::Lit(ref value) => self.lower_lit(value),
312
313             PatKind::Range(ref lo, ref hi, ref end) => {
314                 match (self.lower_lit(lo), self.lower_lit(hi)) {
315                     (PatternKind::Constant { value: lo },
316                      PatternKind::Constant { value: hi }) => {
317                         PatternKind::Range { lo: lo, hi: hi, end: end.clone() }
318                     }
319                     _ => PatternKind::Wild
320                 }
321             }
322
323             PatKind::Path(ref qpath) => {
324                 return self.lower_path(qpath, pat.id, pat.id, pat.span);
325             }
326
327             PatKind::Ref(ref subpattern, _) |
328             PatKind::Box(ref subpattern) => {
329                 PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
330             }
331
332             PatKind::Slice(ref prefix, ref slice, ref suffix) => {
333                 let ty = self.tables.node_id_to_type(pat.id);
334                 match ty.sty {
335                     ty::TyRef(_, mt) =>
336                         PatternKind::Deref {
337                             subpattern: Pattern {
338                                 ty: mt.ty,
339                                 span: pat.span,
340                                 kind: Box::new(self.slice_or_array_pattern(
341                                     pat.span, mt.ty, prefix, slice, suffix))
342                             },
343                         },
344
345                     ty::TySlice(..) |
346                     ty::TyArray(..) =>
347                         self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
348
349                     ref sty =>
350                         span_bug!(
351                             pat.span,
352                             "unexpanded type for vector pattern: {:?}",
353                             sty),
354                 }
355             }
356
357             PatKind::Tuple(ref subpatterns, ddpos) => {
358                 let ty = self.tables.node_id_to_type(pat.id);
359                 match ty.sty {
360                     ty::TyTuple(ref tys, _) => {
361                         let subpatterns =
362                             subpatterns.iter()
363                                        .enumerate_and_adjust(tys.len(), ddpos)
364                                        .map(|(i, subpattern)| FieldPattern {
365                                             field: Field::new(i),
366                                             pattern: self.lower_pattern(subpattern)
367                                        })
368                                        .collect();
369
370                         PatternKind::Leaf { subpatterns: subpatterns }
371                     }
372
373                     ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
374                 }
375             }
376
377             PatKind::Binding(bm, def_id, ref ident, ref sub) => {
378                 let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
379                 let var_ty = self.tables.node_id_to_type(pat.id);
380                 let region = match var_ty.sty {
381                     ty::TyRef(r, _) => Some(r),
382                     _ => None,
383                 };
384                 let (mutability, mode) = match bm {
385                     hir::BindByValue(hir::MutMutable) =>
386                         (Mutability::Mut, BindingMode::ByValue),
387                     hir::BindByValue(hir::MutImmutable) =>
388                         (Mutability::Not, BindingMode::ByValue),
389                     hir::BindByRef(hir::MutMutable) =>
390                         (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
391                     hir::BindByRef(hir::MutImmutable) =>
392                         (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
393                 };
394
395                 // A ref x pattern is the same node used for x, and as such it has
396                 // x's type, which is &T, where we want T (the type being matched).
397                 if let hir::BindByRef(_) = bm {
398                     if let ty::TyRef(_, mt) = ty.sty {
399                         ty = mt.ty;
400                     } else {
401                         bug!("`ref {}` has wrong type {}", ident.node, ty);
402                     }
403                 }
404
405                 PatternKind::Binding {
406                     mutability: mutability,
407                     mode: mode,
408                     name: ident.node,
409                     var: id,
410                     ty: var_ty,
411                     subpattern: self.lower_opt_pattern(sub),
412                 }
413             }
414
415             PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
416                 let def = self.tables.qpath_def(qpath, pat.id);
417                 let adt_def = match ty.sty {
418                     ty::TyAdt(adt_def, _) => adt_def,
419                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
420                 };
421                 let variant_def = adt_def.variant_of_def(def);
422
423                 let subpatterns =
424                         subpatterns.iter()
425                                    .enumerate_and_adjust(variant_def.fields.len(), ddpos)
426                                    .map(|(i, field)| FieldPattern {
427                                        field: Field::new(i),
428                                        pattern: self.lower_pattern(field),
429                                    })
430                                    .collect();
431                 self.lower_variant_or_leaf(def, ty, subpatterns)
432             }
433
434             PatKind::Struct(ref qpath, ref fields, _) => {
435                 let def = self.tables.qpath_def(qpath, pat.id);
436                 let adt_def = match ty.sty {
437                     ty::TyAdt(adt_def, _) => adt_def,
438                     _ => {
439                         span_bug!(
440                             pat.span,
441                             "struct pattern not applied to an ADT");
442                     }
443                 };
444                 let variant_def = adt_def.variant_of_def(def);
445
446                 let subpatterns =
447                     fields.iter()
448                           .map(|field| {
449                               let index = variant_def.index_of_field_named(field.node.name);
450                               let index = index.unwrap_or_else(|| {
451                                   span_bug!(
452                                       pat.span,
453                                       "no field with name {:?}",
454                                       field.node.name);
455                               });
456                               FieldPattern {
457                                   field: Field::new(index),
458                                   pattern: self.lower_pattern(&field.node.pat),
459                               }
460                           })
461                           .collect();
462
463                 self.lower_variant_or_leaf(def, ty, subpatterns)
464             }
465         };
466
467         Pattern {
468             span: pat.span,
469             ty: ty,
470             kind: Box::new(kind),
471         }
472     }
473
474     fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
475         pats.iter().map(|p| self.lower_pattern(p)).collect()
476     }
477
478     fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
479     {
480         pat.as_ref().map(|p| self.lower_pattern(p))
481     }
482
483     fn flatten_nested_slice_patterns(
484         &mut self,
485         prefix: Vec<Pattern<'tcx>>,
486         slice: Option<Pattern<'tcx>>,
487         suffix: Vec<Pattern<'tcx>>)
488         -> (Vec<Pattern<'tcx>>, Option<Pattern<'tcx>>, Vec<Pattern<'tcx>>)
489     {
490         let orig_slice = match slice {
491             Some(orig_slice) => orig_slice,
492             None => return (prefix, slice, suffix)
493         };
494         let orig_prefix = prefix;
495         let orig_suffix = suffix;
496
497         // dance because of intentional borrow-checker stupidity.
498         let kind = *orig_slice.kind;
499         match kind {
500             PatternKind::Slice { prefix, slice, mut suffix } |
501             PatternKind::Array { prefix, slice, mut suffix } => {
502                 let mut orig_prefix = orig_prefix;
503
504                 orig_prefix.extend(prefix);
505                 suffix.extend(orig_suffix);
506
507                 (orig_prefix, slice, suffix)
508             }
509             _ => {
510                 (orig_prefix, Some(Pattern {
511                     kind: box kind, ..orig_slice
512                 }), orig_suffix)
513             }
514         }
515     }
516
517     fn slice_or_array_pattern(
518         &mut self,
519         span: Span,
520         ty: Ty<'tcx>,
521         prefix: &[P<hir::Pat>],
522         slice: &Option<P<hir::Pat>>,
523         suffix: &[P<hir::Pat>])
524         -> PatternKind<'tcx>
525     {
526         let prefix = self.lower_patterns(prefix);
527         let slice = self.lower_opt_pattern(slice);
528         let suffix = self.lower_patterns(suffix);
529         let (prefix, slice, suffix) =
530             self.flatten_nested_slice_patterns(prefix, slice, suffix);
531
532         match ty.sty {
533             ty::TySlice(..) => {
534                 // matching a slice or fixed-length array
535                 PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
536             }
537
538             ty::TyArray(_, len) => {
539                 // fixed-length array
540                 assert!(len >= prefix.len() + suffix.len());
541                 PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
542             }
543
544             _ => {
545                 span_bug!(span, "bad slice pattern type {:?}", ty);
546             }
547         }
548     }
549
550     fn lower_variant_or_leaf(
551         &mut self,
552         def: Def,
553         ty: Ty<'tcx>,
554         subpatterns: Vec<FieldPattern<'tcx>>)
555         -> PatternKind<'tcx>
556     {
557         match def {
558             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
559                 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
560                 let adt_def = self.tcx.adt_def(enum_id);
561                 if adt_def.variants.len() > 1 {
562                     let substs = match ty.sty {
563                         ty::TyAdt(_, substs) |
564                         ty::TyFnDef(_, substs) => substs,
565                         _ => bug!("inappropriate type for def: {:?}", ty.sty),
566                     };
567                     PatternKind::Variant {
568                         adt_def: adt_def,
569                         substs: substs,
570                         variant_index: adt_def.variant_index_with_id(variant_id),
571                         subpatterns: subpatterns,
572                     }
573                 } else {
574                     PatternKind::Leaf { subpatterns: subpatterns }
575                 }
576             }
577
578             Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
579             Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
580                 PatternKind::Leaf { subpatterns: subpatterns }
581             }
582
583             _ => bug!()
584         }
585     }
586
587     fn lower_path(&mut self,
588                   qpath: &hir::QPath,
589                   id: ast::NodeId,
590                   pat_id: ast::NodeId,
591                   span: Span)
592                   -> Pattern<'tcx> {
593         let ty = self.tables.node_id_to_type(id);
594         let def = self.tables.qpath_def(qpath, id);
595         let kind = match def {
596             Def::Const(def_id) | Def::AssociatedConst(def_id) => {
597                 let substs = self.tables.node_substs(id);
598                 match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) {
599                     Some((def_id, substs)) => {
600                         // Enter the inlined constant's tables&substs temporarily.
601                         let old_tables = self.tables;
602                         let old_substs = self.substs;
603                         self.tables = self.tcx.typeck_tables_of(def_id);
604                         self.substs = substs;
605                         let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
606                             self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
607                         } else {
608                             self.tcx.sess.cstore.item_body(self.tcx, def_id)
609                         };
610                         let pat = self.lower_const_expr(&body.value, pat_id, span);
611                         self.tables = old_tables;
612                         self.substs = old_substs;
613                         return pat;
614                     }
615                     None => {
616                         self.errors.push(PatternError::StaticInPattern(span));
617                         PatternKind::Wild
618                     }
619                 }
620             }
621             _ => self.lower_variant_or_leaf(def, ty, vec![]),
622         };
623
624         Pattern {
625             span: span,
626             ty: ty,
627             kind: Box::new(kind),
628         }
629     }
630
631     fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
632         let const_cx = eval::ConstContext::new(self.tcx,
633                                                self.param_env.and(self.substs),
634                                                self.tables);
635         match const_cx.eval(expr) {
636             Ok(value) => {
637                 if let ConstVal::Variant(def_id) = value {
638                     let ty = self.tables.expr_ty(expr);
639                     self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
640                 } else {
641                     PatternKind::Constant { value: value }
642                 }
643             }
644             Err(e) => {
645                 self.errors.push(PatternError::ConstEval(e));
646                 PatternKind::Wild
647             }
648         }
649     }
650
651     fn lower_const_expr(&mut self,
652                         expr: &hir::Expr,
653                         pat_id: ast::NodeId,
654                         span: Span)
655                         -> Pattern<'tcx> {
656         let pat_ty = self.tables.expr_ty(expr);
657         debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
658         match pat_ty.sty {
659             ty::TyFloat(_) => {
660                 self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns");
661             }
662             ty::TyAdt(adt_def, _) if adt_def.is_union() => {
663                 // Matching on union fields is unsafe, we can't hide it in constants
664                 self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
665             }
666             ty::TyAdt(adt_def, _) => {
667                 if !self.tcx.has_attr(adt_def.did, "structural_match") {
668                     let msg = format!("to use a constant of type `{}` in a pattern, \
669                                        `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
670                                       self.tcx.item_path_str(adt_def.did),
671                                       self.tcx.item_path_str(adt_def.did));
672                     self.tcx.sess.span_err(span, &msg);
673                 }
674             }
675             _ => { }
676         }
677         let kind = match expr.node {
678             hir::ExprTup(ref exprs) => {
679                 PatternKind::Leaf {
680                     subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
681                         FieldPattern {
682                             field: Field::new(i),
683                             pattern: self.lower_const_expr(expr, pat_id, span)
684                         }
685                     }).collect()
686                 }
687             }
688
689             hir::ExprCall(ref callee, ref args) => {
690                 let qpath = match callee.node {
691                     hir::ExprPath(ref qpath) => qpath,
692                     _ => bug!()
693                 };
694                 let ty = self.tables.node_id_to_type(callee.id);
695                 let def = self.tables.qpath_def(qpath, callee.id);
696                 match def {
697                     Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
698                     _ => {
699                         let subpatterns = args.iter().enumerate().map(|(i, expr)| {
700                             FieldPattern {
701                                 field: Field::new(i),
702                                 pattern: self.lower_const_expr(expr, pat_id, span)
703                             }
704                         }).collect();
705                         self.lower_variant_or_leaf(def, ty, subpatterns)
706                     }
707                 }
708             }
709
710             hir::ExprStruct(ref qpath, ref fields, None) => {
711                 let def = self.tables.qpath_def(qpath, expr.id);
712                 let adt_def = match pat_ty.sty {
713                     ty::TyAdt(adt_def, _) => adt_def,
714                     _ => {
715                         span_bug!(
716                             expr.span,
717                             "struct expr without ADT type");
718                     }
719                 };
720                 let variant_def = adt_def.variant_of_def(def);
721
722                 let subpatterns =
723                     fields.iter()
724                           .map(|field| {
725                               let index = variant_def.index_of_field_named(field.name.node);
726                               let index = index.unwrap_or_else(|| {
727                                   span_bug!(
728                                       expr.span,
729                                       "no field with name {:?}",
730                                       field.name);
731                               });
732                               FieldPattern {
733                                   field: Field::new(index),
734                                   pattern: self.lower_const_expr(&field.expr, pat_id, span),
735                               }
736                           })
737                           .collect();
738
739                 self.lower_variant_or_leaf(def, pat_ty, subpatterns)
740             }
741
742             hir::ExprArray(ref exprs) => {
743                 let pats = exprs.iter()
744                                 .map(|expr| self.lower_const_expr(expr, pat_id, span))
745                                 .collect();
746                 PatternKind::Array {
747                     prefix: pats,
748                     slice: None,
749                     suffix: vec![]
750                 }
751             }
752
753             hir::ExprPath(ref qpath) => {
754                 return self.lower_path(qpath, expr.id, pat_id, span);
755             }
756
757             _ => self.lower_lit(expr)
758         };
759
760         Pattern {
761             span: span,
762             ty: pat_ty,
763             kind: Box::new(kind),
764         }
765     }
766 }
767
768 pub trait PatternFoldable<'tcx> : Sized {
769     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
770         self.super_fold_with(folder)
771     }
772
773     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
774 }
775
776 pub trait PatternFolder<'tcx> : Sized {
777     fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
778         pattern.super_fold_with(self)
779     }
780
781     fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
782         kind.super_fold_with(self)
783     }
784 }
785
786
787 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
788     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
789         let content: T = (**self).fold_with(folder);
790         box content
791     }
792 }
793
794 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
795     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
796         self.iter().map(|t| t.fold_with(folder)).collect()
797     }
798 }
799
800 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
801     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
802         self.as_ref().map(|t| t.fold_with(folder))
803     }
804 }
805
806 macro_rules! CloneImpls {
807     (<$lt_tcx:tt> $($ty:ty),+) => {
808         $(
809             impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
810                 fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
811                     Clone::clone(self)
812                 }
813             }
814         )+
815     }
816 }
817
818 CloneImpls!{ <'tcx>
819     Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>,
820     Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
821     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
822 }
823
824 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
825     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
826         FieldPattern {
827             field: self.field.fold_with(folder),
828             pattern: self.pattern.fold_with(folder)
829         }
830     }
831 }
832
833 impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
834     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
835         folder.fold_pattern(self)
836     }
837
838     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
839         Pattern {
840             ty: self.ty.fold_with(folder),
841             span: self.span.fold_with(folder),
842             kind: self.kind.fold_with(folder)
843         }
844     }
845 }
846
847 impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
848     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
849         folder.fold_pattern_kind(self)
850     }
851
852     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
853         match *self {
854             PatternKind::Wild => PatternKind::Wild,
855             PatternKind::Binding {
856                 mutability,
857                 name,
858                 mode,
859                 var,
860                 ty,
861                 ref subpattern,
862             } => PatternKind::Binding {
863                 mutability: mutability.fold_with(folder),
864                 name: name.fold_with(folder),
865                 mode: mode.fold_with(folder),
866                 var: var.fold_with(folder),
867                 ty: ty.fold_with(folder),
868                 subpattern: subpattern.fold_with(folder),
869             },
870             PatternKind::Variant {
871                 adt_def,
872                 substs,
873                 variant_index,
874                 ref subpatterns,
875             } => PatternKind::Variant {
876                 adt_def: adt_def.fold_with(folder),
877                 substs: substs.fold_with(folder),
878                 variant_index: variant_index.fold_with(folder),
879                 subpatterns: subpatterns.fold_with(folder)
880             },
881             PatternKind::Leaf {
882                 ref subpatterns,
883             } => PatternKind::Leaf {
884                 subpatterns: subpatterns.fold_with(folder),
885             },
886             PatternKind::Deref {
887                 ref subpattern,
888             } => PatternKind::Deref {
889                 subpattern: subpattern.fold_with(folder),
890             },
891             PatternKind::Constant {
892                 ref value
893             } => PatternKind::Constant {
894                 value: value.fold_with(folder)
895             },
896             PatternKind::Range {
897                 ref lo,
898                 ref hi,
899                 ref end,
900             } => PatternKind::Range {
901                 lo: lo.fold_with(folder),
902                 hi: hi.fold_with(folder),
903                 end: end.clone(),
904             },
905             PatternKind::Slice {
906                 ref prefix,
907                 ref slice,
908                 ref suffix,
909             } => PatternKind::Slice {
910                 prefix: prefix.fold_with(folder),
911                 slice: slice.fold_with(folder),
912                 suffix: suffix.fold_with(folder)
913             },
914             PatternKind::Array {
915                 ref prefix,
916                 ref slice,
917                 ref suffix
918             } => PatternKind::Array {
919                 prefix: prefix.fold_with(folder),
920                 slice: slice.fold_with(folder),
921                 suffix: suffix.fold_with(folder)
922             },
923         }
924     }
925 }