about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_const_eval/_match.rs145
-rw-r--r--src/librustc_const_eval/check_match.rs43
-rw-r--r--src/librustc_const_eval/eval.rs130
-rw-r--r--src/librustc_const_eval/pattern.rs386
4 files changed, 411 insertions, 293 deletions
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index ebe10349011..6d04975f533 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -23,18 +23,12 @@ use rustc_data_structures::indexed_vec::Idx;
 use pattern::{FieldPattern, Pattern, PatternKind};
 use pattern::{PatternFoldable, PatternFolder};
 
-use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
-use rustc::hir;
-use rustc::hir::def::CtorKind;
-use rustc::hir::{Pat, PatKind};
+use rustc::mir::Field;
 use rustc::util::common::ErrorReported;
 
-use syntax::ast::{self, DUMMY_NODE_ID};
-use syntax::codemap::Spanned;
-use syntax::ptr::P;
 use syntax_pos::{Span, DUMMY_SP};
 
 use arena::TypedArena;
@@ -74,12 +68,6 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
     }
 }
 
-pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
-    id: DUMMY_NODE_ID,
-    node: PatKind::Wild,
-    span: DUMMY_SP
-};
-
 impl<'tcx> Pattern<'tcx> {
     fn is_wildcard(&self) -> bool {
         match *self.kind {
@@ -224,25 +212,34 @@ pub enum Constructor {
 }
 
 impl<'tcx> Constructor {
-    fn variant_for_adt(&self, adt: &'tcx ty::AdtDef) -> &'tcx ty::VariantDef {
+    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
         match self {
-            &Variant(vid) => adt.variant_with_id(vid),
+            &Variant(vid) => adt.variant_index_with_id(vid),
             &Single => {
                 assert_eq!(adt.variants.len(), 1);
-                &adt.variants[0]
+                0
             }
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
         }
     }
 }
 
-#[derive(Clone, PartialEq)]
-pub enum Usefulness {
+#[derive(Clone)]
+pub enum Usefulness<'tcx> {
     Useful,
-    UsefulWithWitness(Vec<Witness>),
+    UsefulWithWitness(Vec<Witness<'tcx>>),
     NotUseful
 }
 
+impl<'tcx> Usefulness<'tcx> {
+    fn is_useful(&self) -> bool {
+        match *self {
+            NotUseful => false,
+            _ => true
+        }
+    }
+}
+
 #[derive(Copy, Clone)]
 pub enum WitnessPreference {
     ConstructWitness,
@@ -255,31 +252,17 @@ struct PatternContext<'tcx> {
     max_slice_length: usize,
 }
 
-
-fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
-    let node = match value {
-        &ConstVal::Bool(b) => ast::LitKind::Bool(b),
-        _ => bug!()
-    };
-    P(hir::Expr {
-        id: DUMMY_NODE_ID,
-        node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
-        span: DUMMY_SP,
-        attrs: ast::ThinVec::new(),
-    })
-}
-
 /// A stack of patterns in reverse order of construction
-#[derive(Clone, PartialEq, Eq)]
-pub struct Witness(Vec<P<Pat>>);
+#[derive(Clone)]
+pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
 
-impl Witness {
-    pub fn single_pattern(&self) -> &Pat {
+impl<'tcx> Witness<'tcx> {
+    pub fn single_pattern(&self) -> &Pattern<'tcx> {
         assert_eq!(self.0.len(), 1);
         &self.0[0]
     }
 
-    fn push_wild_constructor<'a, 'tcx>(
+    fn push_wild_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
         ctor: &Constructor,
@@ -287,7 +270,7 @@ impl Witness {
         -> Self
     {
         let arity = constructor_arity(cx, ctor, ty);
-        self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone())));
+        self.0.extend(repeat(cx.wild_pattern).take(arity).cloned());
         self.apply_constructor(cx, ctor, ty)
     }
 
@@ -305,7 +288,7 @@ impl Witness {
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'a, 'tcx>(
+    fn apply_constructor<'a>(
         mut self,
         cx: &MatchCheckCtxt<'a,'tcx>,
         ctor: &Constructor,
@@ -318,60 +301,56 @@ impl Witness {
             let mut pats = self.0.drain(len-arity..).rev();
 
             match ty.sty {
-                ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
-
-                ty::TyAdt(adt, _) => {
-                    let v = ctor.variant_for_adt(adt);
-                    let qpath = hir::QPath::Resolved(None, P(hir::Path {
-                        span: DUMMY_SP,
-                        def: Def::Err,
-                        segments: vec![hir::PathSegment::from_name(v.name)].into(),
-                    }));
-                    match v.ctor_kind {
-                        CtorKind::Fictive => {
-                            let field_pats: hir::HirVec<_> = v.fields.iter()
-                                .zip(pats)
-                                .filter(|&(_, ref pat)| pat.node != PatKind::Wild)
-                                .map(|(field, pat)| Spanned {
-                                    span: DUMMY_SP,
-                                    node: hir::FieldPat {
-                                        name: field.name,
-                                        pat: pat,
-                                        is_shorthand: false,
-                                    }
-                                }).collect();
-                            let has_more_fields = field_pats.len() < arity;
-                            PatKind::Struct(qpath, field_pats, has_more_fields)
+                ty::TyAdt(..) |
+                ty::TyTuple(..) => {
+                    let pats = pats.enumerate().map(|(i, p)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: p
                         }
-                        CtorKind::Fn => {
-                            PatKind::TupleStruct(qpath, pats.collect(), None)
+                    }).collect();
+
+                    if let ty::TyAdt(adt, _) = ty.sty {
+                        if adt.variants.len() > 1 {
+                            PatternKind::Variant {
+                                adt_def: adt,
+                                variant_index: ctor.variant_index_for_adt(adt),
+                                subpatterns: pats
+                            }
+                        } else {
+                            PatternKind::Leaf { subpatterns: pats }
                         }
-                        CtorKind::Const => PatKind::Path(qpath)
+                    } else {
+                        PatternKind::Leaf { subpatterns: pats }
                     }
                 }
 
-                ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
-                    PatKind::Ref(pats.nth(0).unwrap(), mutbl)
+                ty::TyRef(..) => {
+                    PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
                 }
 
                 ty::TySlice(_) | ty::TyArray(..) => {
-                    PatKind::Slice(pats.collect(), None, hir::HirVec::new())
+                    PatternKind::Slice {
+                        prefix: pats.collect(),
+                        slice: None,
+                        suffix: vec![]
+                    }
                 }
 
                 _ => {
                     match *ctor {
-                        ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)),
-                        _ => PatKind::Wild,
+                        ConstantValue(ref v) => PatternKind::Constant { value: v.clone() },
+                        _ => PatternKind::Wild,
                     }
                 }
             }
         };
 
-        self.0.push(P(hir::Pat {
-            id: DUMMY_NODE_ID,
-            node: pat,
-            span: DUMMY_SP
-        }));
+        self.0.push(Pattern {
+            ty: ty,
+            span: DUMMY_SP,
+            kind: Box::new(pat),
+        });
 
         self
     }
@@ -528,13 +507,13 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                            matrix: &Matrix<'a, 'tcx>,
                            v: &[&'a Pattern<'tcx>],
                            witness: WitnessPreference)
-                           -> Usefulness {
+                           -> Usefulness<'tcx> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:?}, {:?})", matrix, v);
     if rows.is_empty() {
         return match witness {
             ConstructWitness => UsefulWithWitness(vec![Witness(
-                repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect()
+                repeat(cx.wild_pattern).take(v.len()).cloned().collect()
             )]),
             LeaveOutWitness => Useful
         };
@@ -559,7 +538,7 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         debug!("is_useful - expanding constructors: {:?}", constructors);
         constructors.into_iter().map(|c|
             is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
-        ).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+        ).find(|result| result.is_useful()).unwrap_or(NotUseful)
     } else {
         debug!("is_useful - expanding wildcard");
         let constructors = missing_constructors(cx, matrix, pcx);
@@ -567,7 +546,7 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
         if constructors.is_empty() {
             all_constructors(cx, pcx).into_iter().map(|c| {
                 is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
-            }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+            }).find(|result| result.is_useful()).unwrap_or(NotUseful)
         } else {
             let matrix = rows.iter().filter_map(|r| {
                 if r[0].is_wildcard() {
@@ -597,7 +576,7 @@ fn is_useful_specialized<'a, 'tcx>(
     v: &[&'a Pattern<'tcx>],
     ctor: Constructor,
     lty: Ty<'tcx>,
-    witness: WitnessPreference) -> Usefulness
+    witness: WitnessPreference) -> Usefulness<'tcx>
 {
     let arity = constructor_arity(cx, &ctor, lty);
     let matrix = Matrix(m.iter().flat_map(|r| {
@@ -672,7 +651,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
         },
         ty::TyRef(..) => 1,
         ty::TyAdt(adt, _) => {
-            ctor.variant_for_adt(adt).fields.len()
+            adt.variants[ctor.variant_index_for_adt(adt)].fields.len()
         }
         _ => 0
     }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 01b19e1f539..53e83815b46 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -9,11 +9,10 @@
 // except according to those terms.
 
 use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
-use _match::{DUMMY_WILD_PAT};
 use _match::Usefulness::*;
 use _match::WitnessPreference::*;
 
-use pattern::{Pattern, PatternContext, PatternError};
+use pattern::{Pattern, PatternContext, PatternError, PatternKind};
 
 use eval::report_const_eval_err;
 
@@ -117,13 +116,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
     fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
         for error in patcx.errors {
             match error {
-                PatternError::BadConstInPattern(span, def_id) => {
-                    self.tcx.sess.span_err(
-                        span,
-                        &format!("constants of the type `{}` \
-                                  cannot be used in patterns",
-                                 self.tcx.item_path_str(def_id)));
-                }
                 PatternError::StaticInPattern(span) => {
                     span_err!(self.tcx.sess, span, E0158,
                               "statics cannot be referenced in patterns");
@@ -230,9 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 Useful => bug!()
             };
 
-            let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
-                s.print_pat(witness[0].single_pattern())
-            });
+            let pattern_string = witness[0].single_pattern().to_string();
             let mut diag = struct_span_err!(
                 self.tcx.sess, pat.span, E0005,
                 "refutable pattern in {}: `{}` not covered",
@@ -369,23 +359,21 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
         UsefulWithWitness(pats) => {
             let witnesses = if pats.is_empty() {
-                vec![DUMMY_WILD_PAT]
+                vec![cx.wild_pattern]
             } else {
                 pats.iter().map(|w| w.single_pattern()).collect()
             };
             match source {
                 hir::MatchSource::ForLoopDesugar => {
                     // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
-                    let witness = match witnesses[0].node {
-                        PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
-                            &[ref pat] => &**pat,
+                    let witness = match *witnesses[0].kind {
+                        PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] {
+                            &[ref pat] => &pat.pattern,
                             _ => bug!(),
                         },
                         _ => bug!(),
                     };
-                    let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
-                        s.print_pat(witness)
-                    });
+                    let pattern_string = witness.to_string();
                     struct_span_err!(cx.tcx.sess, sp, E0297,
                         "refutable pattern in `for` loop binding: \
                                 `{}` not covered",
@@ -394,24 +382,23 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                         .emit();
                 },
                 _ => {
-                    let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
-                        hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
-                    }).collect();
                     const LIMIT: usize = 3;
-                    let joined_patterns = match pattern_strings.len() {
+                    let joined_patterns = match witnesses.len() {
                         0 => bug!(),
-                        1 => format!("`{}`", pattern_strings[0]),
+                        1 => format!("`{}`", witnesses[0]),
                         2...LIMIT => {
-                            let (tail, head) = pattern_strings.split_last().unwrap();
-                            format!("`{}`", head.join("`, `") + "` and `" + tail)
+                            let (tail, head) = witnesses.split_last().unwrap();
+                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                            format!("`{}` and `{}`", head.join("`, `"), tail)
                         },
                         _ => {
-                            let (head, tail) = pattern_strings.split_at(LIMIT);
+                            let (head, tail) = witnesses.split_at(LIMIT);
+                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
                             format!("`{}` and {} more", head.join("`, `"), tail.len())
                         }
                     };
 
-                    let label_text = match pattern_strings.len(){
+                    let label_text = match witnesses.len() {
                         1 => format!("pattern {} not covered", joined_patterns),
                         _ => format!("patterns {} not covered", joined_patterns)
                     };
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c736b4865e7..6b8e0e34c1d 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -18,7 +18,7 @@ use self::EvalHint::*;
 use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
@@ -26,16 +26,12 @@ use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
 use rustc::util::nodemap::DefIdMap;
-use rustc::lint;
 
 use graphviz::IntoCow;
 use syntax::ast;
-use rustc::hir::{Expr, PatKind};
-use rustc::hir;
-use syntax::ptr::P;
-use syntax::codemap;
+use rustc::hir::{self, Expr};
 use syntax::attr::IntType;
-use syntax_pos::{self, Span};
+use syntax_pos::Span;
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
@@ -186,126 +182,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 }
 
-pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   expr: &Expr,
-                                   pat_id: ast::NodeId,
-                                   span: Span)
-                                   -> Result<P<hir::Pat>, DefId> {
-    let pat_ty = tcx.tables().expr_ty(expr);
-    debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
-    match pat_ty.sty {
-        ty::TyFloat(_) => {
-            tcx.sess.add_lint(
-                lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
-                pat_id,
-                span,
-                format!("floating point constants cannot be used in patterns"));
-        }
-        ty::TyAdt(adt_def, _) if adt_def.is_union() => {
-            // Matching on union fields is unsafe, we can't hide it in constants
-            tcx.sess.span_err(span, "cannot use unions in constant patterns");
-        }
-        ty::TyAdt(adt_def, _) => {
-            if !tcx.has_attr(adt_def.did, "structural_match") {
-                tcx.sess.add_lint(
-                    lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
-                    pat_id,
-                    span,
-                    format!("to use a constant of type `{}` \
-                             in a pattern, \
-                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                            tcx.item_path_str(adt_def.did),
-                            tcx.item_path_str(adt_def.did)));
-            }
-        }
-        _ => { }
-    }
-    let pat = match expr.node {
-        hir::ExprTup(ref exprs) =>
-            PatKind::Tuple(exprs.iter()
-                                .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                                .collect::<Result<_, _>>()?, None),
-
-        hir::ExprCall(ref callee, ref args) => {
-            let qpath = match callee.node {
-                hir::ExprPath(ref qpath) => qpath,
-                _ => bug!()
-            };
-            let def = tcx.tables().qpath_def(qpath, callee.id);
-            let ctor_path = if let hir::QPath::Resolved(_, ref path) = *qpath {
-                match def {
-                    Def::StructCtor(_, CtorKind::Fn) |
-                    Def::VariantCtor(_, CtorKind::Fn) => {
-                        Some(path.clone())
-                    }
-                    _ => None
-                }
-            } else {
-                None
-            };
-            match (def, ctor_path) {
-                (Def::Fn(..), None) | (Def::Method(..), None) => {
-                    PatKind::Lit(P(expr.clone()))
-                }
-                (_, Some(ctor_path)) => {
-                    let pats = args.iter()
-                                   .map(|expr| const_expr_to_pat(tcx, expr, pat_id, span))
-                                   .collect::<Result<_, _>>()?;
-                    PatKind::TupleStruct(hir::QPath::Resolved(None, ctor_path), pats, None)
-                }
-                _ => bug!()
-            }
-        }
-
-        hir::ExprStruct(ref qpath, ref fields, None) => {
-            let field_pats =
-                fields.iter()
-                      .map(|field| Ok(codemap::Spanned {
-                          span: syntax_pos::DUMMY_SP,
-                          node: hir::FieldPat {
-                              name: field.name.node,
-                              pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?,
-                              is_shorthand: false,
-                          },
-                      }))
-                      .collect::<Result<_, _>>()?;
-            PatKind::Struct(qpath.clone(), field_pats, false)
-        }
-
-        hir::ExprArray(ref exprs) => {
-            let pats = exprs.iter()
-                            .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span))
-                            .collect::<Result<_, _>>()?;
-            PatKind::Slice(pats, None, hir::HirVec::new())
-        }
-
-        hir::ExprPath(ref qpath) => {
-            let def = tcx.tables().qpath_def(qpath, expr.id);
-            match def {
-                Def::StructCtor(_, CtorKind::Const) |
-                Def::VariantCtor(_, CtorKind::Const) => {
-                    match expr.node {
-                        hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-                            PatKind::Path(hir::QPath::Resolved(None, path.clone()))
-                        }
-                        _ => bug!()
-                    }
-                }
-                Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                    let substs = Some(tcx.tables().node_id_item_substs(expr.id)
-                        .unwrap_or_else(|| tcx.intern_substs(&[])));
-                    let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
-                    return const_expr_to_pat(tcx, expr, pat_id, span);
-                },
-                _ => bug!(),
-            }
-        }
-
-        _ => PatKind::Lit(P(expr.clone()))
-    };
-    Ok(P(hir::Pat { id: expr.id, node: pat, span: span }))
-}
-
 pub fn report_const_eval_err<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     err: &ConstEvalErr,
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index e93178c89c2..b122d97a702 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -10,16 +10,17 @@
 
 use eval;
 
+use rustc::lint;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::{Field, BorrowKind, Mutability};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
 use rustc::hir::{self, PatKind};
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
 
+use std::fmt;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax_pos::Span;
@@ -27,7 +28,6 @@ use syntax_pos::Span;
 #[derive(Clone, Debug)]
 pub enum PatternError {
     StaticInPattern(Span),
-    BadConstInPattern(Span, DefId),
     ConstEval(eval::ConstEvalErr),
 }
 
@@ -105,6 +105,158 @@ pub enum PatternKind<'tcx> {
     },
 }
 
+fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
+    match *value {
+        ConstVal::Float(ref x) => write!(f, "{}", x),
+        ConstVal::Integral(ref i) => write!(f, "{}", i),
+        ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
+        ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
+        ConstVal::Bool(b) => write!(f, "{:?}", b),
+        ConstVal::Char(c) => write!(f, "{:?}", c),
+        ConstVal::Struct(_) |
+        ConstVal::Tuple(_) |
+        ConstVal::Function(_) |
+        ConstVal::Array(..) |
+        ConstVal::Repeat(..) |
+        ConstVal::Dummy => bug!("{:?} not printable in a pattern", value)
+    }
+}
+
+impl<'tcx> fmt::Display for Pattern<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self.kind {
+            PatternKind::Wild => write!(f, "_"),
+            PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+                let is_mut = match mode {
+                    BindingMode::ByValue => mutability == Mutability::Mut,
+                    BindingMode::ByRef(_, bk) => {
+                        write!(f, "ref ")?;
+                        bk == BorrowKind::Mut
+                    }
+                };
+                if is_mut {
+                    write!(f, "mut ")?;
+                }
+                write!(f, "{}", name)?;
+                if let Some(ref subpattern) = *subpattern {
+                    write!(f, " @ {}", subpattern)?;
+                }
+                Ok(())
+            }
+            PatternKind::Variant { ref subpatterns, .. } |
+            PatternKind::Leaf { ref subpatterns } => {
+                let variant = match *self.kind {
+                    PatternKind::Variant { adt_def, variant_index, .. } => {
+                        Some(&adt_def.variants[variant_index])
+                    }
+                    _ => if let ty::TyAdt(adt, _) = self.ty.sty {
+                        Some(adt.struct_variant())
+                    } else {
+                        None
+                    }
+                };
+
+                let mut first = true;
+                let mut start_or_continue = || if first { first = false; "" } else { ", " };
+
+                if let Some(variant) = variant {
+                    write!(f, "{}", variant.name)?;
+
+                    // Only for TyAdt we can have `S {...}`,
+                    // which we handle separately here.
+                    if variant.ctor_kind == CtorKind::Fictive {
+                        write!(f, " {{ ")?;
+
+                        let mut printed = 0;
+                        for p in subpatterns {
+                            if let PatternKind::Wild = *p.pattern.kind {
+                                continue;
+                            }
+                            let name = variant.fields[p.field.index()].name;
+                            write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?;
+                            printed += 1;
+                        }
+
+                        if printed < variant.fields.len() {
+                            write!(f, "{}..", start_or_continue())?;
+                        }
+
+                        return write!(f, " }}");
+                    }
+                }
+
+                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+                if num_fields != 0 || variant.is_none() {
+                    write!(f, "(")?;
+                    for i in 0..num_fields {
+                        write!(f, "{}", start_or_continue())?;
+
+                        // Common case: the field is where we expect it.
+                        if let Some(p) = subpatterns.get(i) {
+                            if p.field.index() == i {
+                                write!(f, "{}", p.pattern)?;
+                                continue;
+                            }
+                        }
+
+                        // Otherwise, we have to go looking for it.
+                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                            write!(f, "{}", p.pattern)?;
+                        } else {
+                            write!(f, "_")?;
+                        }
+                    }
+                    write!(f, ")")?;
+                }
+
+                Ok(())
+            }
+            PatternKind::Deref { ref subpattern } => {
+                match self.ty.sty {
+                    ty::TyBox(_) => write!(f, "box ")?,
+                    ty::TyRef(_, mt) => {
+                        write!(f, "&")?;
+                        if mt.mutbl == hir::MutMutable {
+                            write!(f, "mut ")?;
+                        }
+                    }
+                    _ => bug!("{} is a bad Deref pattern type", self.ty)
+                }
+                write!(f, "{}", subpattern)
+            }
+            PatternKind::Constant { ref value } => {
+                print_const_val(value, f)
+            }
+            PatternKind::Range { ref lo, ref hi } => {
+                print_const_val(lo, f)?;
+                write!(f, "...")?;
+                print_const_val(hi, f)
+            }
+            PatternKind::Slice { ref prefix, ref slice, ref suffix } |
+            PatternKind::Array { ref prefix, ref slice, ref suffix } => {
+                let mut first = true;
+                let mut start_or_continue = || if first { first = false; "" } else { ", " };
+                write!(f, "[")?;
+                for p in prefix {
+                    write!(f, "{}{}", start_or_continue(), p)?;
+                }
+                if let Some(ref slice) = *slice {
+                    write!(f, "{}", start_or_continue())?;
+                    match *slice.kind {
+                        PatternKind::Wild => {}
+                        _ => write!(f, "{}", slice)?
+                    }
+                    write!(f, "..")?;
+                }
+                for p in suffix {
+                    write!(f, "{}{}", start_or_continue(), p)?;
+                }
+                write!(f, "]")
+            }
+        }
+    }
+}
+
 pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub errors: Vec<PatternError>,
@@ -133,64 +285,20 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
 
-            PatKind::Lit(ref value) => {
-                match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) {
-                    Ok(value) => {
-                        PatternKind::Constant { value: value }
-                    }
-                    Err(e) => {
-                        self.errors.push(PatternError::ConstEval(e));
-                        PatternKind::Wild
-                    }
-                }
-            }
+            PatKind::Lit(ref value) => self.lower_lit(value),
 
             PatKind::Range(ref lo, ref hi) => {
-                let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo);
-                if let Err(ref e_lo) = r_lo {
-                    self.errors.push(PatternError::ConstEval(e_lo.clone()));
-                }
-
-                let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi);
-                if let Err(ref e_hi) = r_hi {
-                    self.errors.push(PatternError::ConstEval(e_hi.clone()));
-                }
-
-                if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) {
-                    PatternKind::Range { lo: lo, hi: hi }
-                } else {
-                    PatternKind::Wild
+                match (self.lower_lit(lo), self.lower_lit(hi)) {
+                    (PatternKind::Constant { value: lo },
+                     PatternKind::Constant { value: hi }) => {
+                        PatternKind::Range { lo: lo, hi: hi }
+                    }
+                    _ => PatternKind::Wild
                 }
             }
 
             PatKind::Path(ref qpath) => {
-                let def = self.tcx.tables().qpath_def(qpath, pat.id);
-                match def {
-                    Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                        let tcx = self.tcx.global_tcx();
-                        let substs = tcx.tables().node_id_item_substs(pat.id)
-                            .unwrap_or_else(|| tcx.intern_substs(&[]));
-                        match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
-                            Some((const_expr, _const_ty)) => {
-                                match eval::const_expr_to_pat(
-                                    tcx, const_expr, pat.id, pat.span)
-                                {
-                                    Ok(pat) => return self.lower_pattern(&pat),
-                                    Err(_) => {
-                                        self.errors.push(PatternError::BadConstInPattern(
-                                            pat.span, def_id));
-                                        PatternKind::Wild
-                                    }
-                                }
-                            }
-                            None => {
-                                self.errors.push(PatternError::StaticInPattern(pat.span));
-                                PatternKind::Wild
-                            }
-                        }
-                    }
-                    _ => self.lower_variant_or_leaf(def, vec![])
-                }
+                return self.lower_path(qpath, pat.id, pat.id, pat.span);
             }
 
             PatKind::Ref(ref subpattern, _) |
@@ -447,6 +555,174 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
             _ => bug!()
         }
     }
+
+    fn lower_path(&mut self,
+                  qpath: &hir::QPath,
+                  id: ast::NodeId,
+                  pat_id: ast::NodeId,
+                  span: Span)
+                  -> Pattern<'tcx> {
+        let def = self.tcx.tables().qpath_def(qpath, id);
+        let kind = match def {
+            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                let tcx = self.tcx.global_tcx();
+                let substs = tcx.tables().node_id_item_substs(id)
+                    .unwrap_or_else(|| tcx.intern_substs(&[]));
+                match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
+                    Some((const_expr, _const_ty)) => {
+                        return self.lower_const_expr(const_expr, pat_id, span);
+                    }
+                    None => {
+                        self.errors.push(PatternError::StaticInPattern(span));
+                        PatternKind::Wild
+                    }
+                }
+            }
+            _ => self.lower_variant_or_leaf(def, vec![])
+        };
+
+        Pattern {
+            span: span,
+            ty: self.tcx.tables().node_id_to_type(id),
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
+        match eval::eval_const_expr_checked(self.tcx.global_tcx(), expr) {
+            Ok(value) => {
+                PatternKind::Constant { value: value }
+            }
+            Err(e) => {
+                self.errors.push(PatternError::ConstEval(e));
+                PatternKind::Wild
+            }
+        }
+    }
+
+    fn lower_const_expr(&mut self,
+                        expr: &hir::Expr,
+                        pat_id: ast::NodeId,
+                        span: Span)
+                        -> Pattern<'tcx> {
+        let pat_ty = self.tcx.tables().expr_ty(expr);
+        debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id);
+        match pat_ty.sty {
+            ty::TyFloat(_) => {
+                self.tcx.sess.add_lint(
+                    lint::builtin::ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
+                    pat_id,
+                    span,
+                    format!("floating point constants cannot be used in patterns"));
+            }
+            ty::TyAdt(adt_def, _) if adt_def.is_union() => {
+                // Matching on union fields is unsafe, we can't hide it in constants
+                self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
+            }
+            ty::TyAdt(adt_def, _) => {
+                if !self.tcx.has_attr(adt_def.did, "structural_match") {
+                    self.tcx.sess.add_lint(
+                        lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
+                        pat_id,
+                        span,
+                        format!("to use a constant of type `{}` \
+                                 in a pattern, \
+                                 `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                                self.tcx.item_path_str(adt_def.did),
+                                self.tcx.item_path_str(adt_def.did)));
+                }
+            }
+            _ => { }
+        }
+        let kind = match expr.node {
+            hir::ExprTup(ref exprs) => {
+                PatternKind::Leaf {
+                    subpatterns: exprs.iter().enumerate().map(|(i, expr)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: self.lower_const_expr(expr, pat_id, span)
+                        }
+                    }).collect()
+                }
+            }
+
+            hir::ExprCall(ref callee, ref args) => {
+                let qpath = match callee.node {
+                    hir::ExprPath(ref qpath) => qpath,
+                    _ => bug!()
+                };
+                let def = self.tcx.tables().qpath_def(qpath, callee.id);
+                match def {
+                    Def::Fn(..) | Def::Method(..) => self.lower_lit(expr),
+                    _ => {
+                        let subpatterns = args.iter().enumerate().map(|(i, expr)| {
+                            FieldPattern {
+                                field: Field::new(i),
+                                pattern: self.lower_const_expr(expr, pat_id, span)
+                            }
+                        }).collect();
+                        self.lower_variant_or_leaf(def, subpatterns)
+                    }
+                }
+            }
+
+            hir::ExprStruct(ref qpath, ref fields, None) => {
+                let def = self.tcx.tables().qpath_def(qpath, expr.id);
+                let pat_ty = self.tcx.tables().node_id_to_type(expr.id);
+                let adt_def = match pat_ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => {
+                        span_bug!(
+                            expr.span,
+                            "struct expr without ADT type");
+                    }
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                    fields.iter()
+                          .map(|field| {
+                              let index = variant_def.index_of_field_named(field.name.node);
+                              let index = index.unwrap_or_else(|| {
+                                  span_bug!(
+                                      expr.span,
+                                      "no field with name {:?}",
+                                      field.name);
+                              });
+                              FieldPattern {
+                                  field: Field::new(index),
+                                  pattern: self.lower_const_expr(&field.expr, pat_id, span),
+                              }
+                          })
+                          .collect();
+
+                self.lower_variant_or_leaf(def, subpatterns)
+            }
+
+            hir::ExprArray(ref exprs) => {
+                let pats = exprs.iter()
+                                .map(|expr| self.lower_const_expr(expr, pat_id, span))
+                                .collect();
+                PatternKind::Array {
+                    prefix: pats,
+                    slice: None,
+                    suffix: vec![]
+                }
+            }
+
+            hir::ExprPath(ref qpath) => {
+                return self.lower_path(qpath, expr.id, pat_id, span);
+            }
+
+            _ => self.lower_lit(expr)
+        };
+
+        Pattern {
+            span: span,
+            ty: pat_ty,
+            kind: Box::new(kind),
+        }
+    }
 }
 
 pub trait PatternFoldable<'tcx> : Sized {