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