]> git.lizzy.rs Git - rust.git/commitdiff
Move the pattern checking code to hair
authorOliver Schneider <git-no-reply-9879165716479413131@oli-obk.de>
Fri, 26 Jan 2018 15:12:07 +0000 (16:12 +0100)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Thu, 8 Mar 2018 07:34:11 +0000 (08:34 +0100)
12 files changed:
src/librustc_driver/driver.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/hair/pattern/_match.rs [new file with mode: 0644]
src/librustc_mir/hair/pattern/check_match.rs [new file with mode: 0644]
src/librustc_mir/hair/pattern/mod.rs [new file with mode: 0644]
src/librustc_mir/hair/pattern/pattern.rs [new file with mode: 0644]
src/librustc_mir/lib.rs
src/librustc_mir/pattern/_match.rs [deleted file]
src/librustc_mir/pattern/check_match.rs [deleted file]
src/librustc_mir/pattern/mod.rs [deleted file]
src/librustc_mir/pattern/pattern.rs [deleted file]

index d396e92598a9604c364831480c7782ddce73a5cb..f232d039f6641c0a35ef06db7bca9a3d199b7b1a 100644 (file)
@@ -1048,7 +1048,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
 
         time(time_passes,
              "match checking",
-             || mir::pattern::check_crate(tcx));
+             || mir::matchck_crate(tcx));
 
         // this must run before MIR dump, because
         // "not all control paths return a value" is reported here.
index 57508cc43a46ff5bb8609522140d865a5bb01bdc..23c5499bb639648c15a0ac570b531f029087988e 100644 (file)
@@ -11,7 +11,7 @@
 
 use build;
 use hair::cx::Cx;
-use hair::LintLevel;
+use hair::{LintLevel, BindingMode, PatternKind};
 use rustc::hir;
 use rustc::hir::def_id::{DefId, LocalDefId};
 use rustc::middle::region;
@@ -21,7 +21,6 @@
 use rustc::ty::subst::Substs;
 use rustc::util::nodemap::NodeMap;
 use rustc_back::PanicStrategy;
-use pattern::pattern::{BindingMode, PatternKind};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use shim;
 use std::mem;
index 3eeaad8710157c57245ce729181c0f6b4fb20135..5f60a134fb13063bcbfc6594cf444c6ade8a1ed0 100644 (file)
@@ -26,7 +26,8 @@
 
 pub mod cx;
 
-pub use pattern::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
+pub mod pattern;
+pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
 
 #[derive(Copy, Clone, Debug)]
 pub enum LintLevel {
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
new file mode 100644 (file)
index 0000000..7f44389
--- /dev/null
@@ -0,0 +1,1176 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use self::Constructor::*;
+use self::Usefulness::*;
+use self::WitnessPreference::*;
+
+use rustc::middle::const_val::ConstVal;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::indexed_vec::Idx;
+
+use super::{FieldPattern, Pattern, PatternKind};
+use super::{PatternFoldable, PatternFolder, compare_const_vals};
+
+use rustc::hir::def_id::DefId;
+use rustc::hir::RangeEnd;
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+
+use rustc::mir::Field;
+use rustc::mir::interpret::{Value, PrimVal};
+use rustc::util::common::ErrorReported;
+
+use syntax_pos::{Span, DUMMY_SP};
+
+use arena::TypedArena;
+
+use std::cmp::{self, Ordering};
+use std::fmt;
+use std::iter::{FromIterator, IntoIterator, repeat};
+
+pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
+                                -> &'a Pattern<'tcx>
+{
+    cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
+}
+
+struct LiteralExpander;
+impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
+    fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
+        match (&pat.ty.sty, &*pat.kind) {
+            (&ty::TyRef(_, mt), &PatternKind::Constant { ref value }) => {
+                Pattern {
+                    ty: pat.ty,
+                    span: pat.span,
+                    kind: box PatternKind::Deref {
+                        subpattern: Pattern {
+                            ty: mt.ty,
+                            span: pat.span,
+                            kind: box PatternKind::Constant { value: value.clone() },
+                        }
+                    }
+                }
+            }
+            (_, &PatternKind::Binding { subpattern: Some(ref s), .. }) => {
+                s.fold_with(self)
+            }
+            _ => pat.super_fold_with(self)
+        }
+    }
+}
+
+impl<'tcx> Pattern<'tcx> {
+    fn is_wildcard(&self) -> bool {
+        match *self.kind {
+            PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild =>
+                true,
+            _ => false
+        }
+    }
+}
+
+pub struct Matrix<'a, 'tcx: 'a>(Vec<Vec<&'a Pattern<'tcx>>>);
+
+impl<'a, 'tcx> Matrix<'a, 'tcx> {
+    pub fn empty() -> Self {
+        Matrix(vec![])
+    }
+
+    pub fn push(&mut self, row: Vec<&'a Pattern<'tcx>>) {
+        self.0.push(row)
+    }
+}
+
+/// Pretty-printer for matrices of patterns, example:
+/// ++++++++++++++++++++++++++
+/// + _     + []             +
+/// ++++++++++++++++++++++++++
+/// + true  + [First]        +
+/// ++++++++++++++++++++++++++
+/// + true  + [Second(true)] +
+/// ++++++++++++++++++++++++++
+/// + false + [_]            +
+/// ++++++++++++++++++++++++++
+/// + _     + [_, _, ..tail] +
+/// ++++++++++++++++++++++++++
+impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "\n")?;
+
+        let &Matrix(ref m) = self;
+        let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
+            row.iter().map(|pat| format!("{:?}", pat)).collect()
+        }).collect();
+
+        let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
+        assert!(m.iter().all(|row| row.len() == column_count));
+        let column_widths: Vec<usize> = (0..column_count).map(|col| {
+            pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)
+        }).collect();
+
+        let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
+        let br = repeat('+').take(total_width).collect::<String>();
+        write!(f, "{}\n", br)?;
+        for row in pretty_printed_matrix {
+            write!(f, "+")?;
+            for (column, pat_str) in row.into_iter().enumerate() {
+                write!(f, " ")?;
+                write!(f, "{:1$}", pat_str, column_widths[column])?;
+                write!(f, " +")?;
+            }
+            write!(f, "\n")?;
+            write!(f, "{}\n", br)?;
+        }
+        Ok(())
+    }
+}
+
+impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
+    fn from_iter<T: IntoIterator<Item=Vec<&'a Pattern<'tcx>>>>(iter: T) -> Self
+    {
+        Matrix(iter.into_iter().collect())
+    }
+}
+
+//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
+pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    /// The module in which the match occurs. This is necessary for
+    /// checking inhabited-ness of types because whether a type is (visibly)
+    /// inhabited can depend on whether it was defined in the current module or
+    /// not. eg. `struct Foo { _private: ! }` cannot be seen to be empty
+    /// outside it's module and should not be matchable with an empty match
+    /// statement.
+    pub module: DefId,
+    pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
+    pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>,
+}
+
+impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
+    pub fn create_and_enter<F, R>(
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        module: DefId,
+        f: F) -> R
+        where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
+    {
+        let pattern_arena = TypedArena::new();
+
+        f(MatchCheckCtxt {
+            tcx,
+            module,
+            pattern_arena: &pattern_arena,
+            byte_array_map: FxHashMap(),
+        })
+    }
+
+    // convert a byte-string pattern to a list of u8 patterns.
+    fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
+            where 'a: 'p
+    {
+        let pattern_arena = &*self.pattern_arena;
+        let tcx = self.tcx;
+        self.byte_array_map.entry(pat).or_insert_with(|| {
+            match pat.kind {
+                box PatternKind::Constant {
+                    value: &ty::Const { val: ConstVal::Value(b), ty }
+                } => {
+                    match b {
+                        Value::ByVal(PrimVal::Ptr(ptr)) => {
+                            let is_array_ptr = ty
+                                .builtin_deref(true, ty::NoPreference)
+                                .and_then(|t| t.ty.builtin_index())
+                                .map_or(false, |t| t == tcx.types.u8);
+                            assert!(is_array_ptr);
+                            let alloc = tcx
+                                .interpret_interner
+                                .get_alloc(ptr.alloc_id)
+                                .unwrap();
+                            assert_eq!(ptr.offset, 0);
+                            // FIXME: check length
+                            alloc.bytes.iter().map(|b| {
+                                &*pattern_arena.alloc(Pattern {
+                                    ty: tcx.types.u8,
+                                    span: pat.span,
+                                    kind: box PatternKind::Constant {
+                                        value: tcx.mk_const(ty::Const {
+                                            val: ConstVal::Value(Value::ByVal(
+                                                PrimVal::Bytes(*b as u128),
+                                            )),
+                                            ty: tcx.types.u8
+                                        })
+                                    }
+                                })
+                            }).collect()
+                        },
+                        _ => bug!("not a byte str: {:?}", b),
+                    }
+                }
+                _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
+            }
+        }).clone()
+    }
+
+    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+        if self.tcx.features().never_type {
+            self.tcx.is_ty_uninhabited_from(self.module, ty)
+        } else {
+            false
+        }
+    }
+
+    fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+        match ty.sty {
+            ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
+            _ => false,
+        }
+    }
+
+    fn is_local(&self, ty: Ty<'tcx>) -> bool {
+        match ty.sty {
+            ty::TyAdt(adt_def, ..) => adt_def.did.is_local(),
+            _ => false,
+        }
+    }
+
+    fn is_variant_uninhabited(&self,
+                              variant: &'tcx ty::VariantDef,
+                              substs: &'tcx ty::subst::Substs<'tcx>)
+                              -> bool
+    {
+        if self.tcx.features().never_type {
+            self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
+        } else {
+            false
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Constructor<'tcx> {
+    /// The constructor of all patterns that don't vary by constructor,
+    /// e.g. struct patterns and fixed-length arrays.
+    Single,
+    /// Enum variants.
+    Variant(DefId),
+    /// Literal values.
+    ConstantValue(&'tcx ty::Const<'tcx>),
+    /// Ranges of literal values (`2...5` and `2..5`).
+    ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    /// Array patterns of length n.
+    Slice(u64),
+}
+
+impl<'tcx> Constructor<'tcx> {
+    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
+        match self {
+            &Variant(vid) => adt.variant_index_with_id(vid),
+            &Single => {
+                assert!(!adt.is_enum());
+                0
+            }
+            _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
+        }
+    }
+}
+
+#[derive(Clone)]
+pub enum Usefulness<'tcx> {
+    Useful,
+    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,
+    LeaveOutWitness
+}
+
+#[derive(Copy, Clone, Debug)]
+struct PatternContext<'tcx> {
+    ty: Ty<'tcx>,
+    max_slice_length: u64,
+}
+
+/// A stack of patterns in reverse order of construction
+#[derive(Clone)]
+pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
+
+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>(
+        mut self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        ctor: &Constructor<'tcx>,
+        ty: Ty<'tcx>)
+        -> Self
+    {
+        let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty);
+        self.0.extend(sub_pattern_tys.into_iter().map(|ty| {
+            Pattern {
+                ty,
+                span: DUMMY_SP,
+                kind: box PatternKind::Wild,
+            }
+        }));
+        self.apply_constructor(cx, ctor, ty)
+    }
+
+
+    /// Constructs a partial witness for a pattern given a list of
+    /// patterns expanded by the specialization step.
+    ///
+    /// When a pattern P is discovered to be useful, this function is used bottom-up
+    /// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
+    /// of values, V, where each value in that set is not covered by any previously
+    /// used patterns and is covered by the pattern P'. Examples:
+    ///
+    /// left_ty: tuple of 3 elements
+    /// pats: [10, 20, _]           => (10, 20, _)
+    ///
+    /// left_ty: struct X { a: (bool, &'static str), b: usize}
+    /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
+    fn apply_constructor<'a>(
+        mut self,
+        cx: &MatchCheckCtxt<'a,'tcx>,
+        ctor: &Constructor<'tcx>,
+        ty: Ty<'tcx>)
+        -> Self
+    {
+        let arity = constructor_arity(cx, ctor, ty);
+        let pat = {
+            let len = self.0.len() as u64;
+            let mut pats = self.0.drain((len-arity) as usize..).rev();
+
+            match ty.sty {
+                ty::TyAdt(..) |
+                ty::TyTuple(..) => {
+                    let pats = pats.enumerate().map(|(i, p)| {
+                        FieldPattern {
+                            field: Field::new(i),
+                            pattern: p
+                        }
+                    }).collect();
+
+                    if let ty::TyAdt(adt, substs) = ty.sty {
+                        if adt.is_enum() {
+                            PatternKind::Variant {
+                                adt_def: adt,
+                                substs,
+                                variant_index: ctor.variant_index_for_adt(adt),
+                                subpatterns: pats
+                            }
+                        } else {
+                            PatternKind::Leaf { subpatterns: pats }
+                        }
+                    } else {
+                        PatternKind::Leaf { subpatterns: pats }
+                    }
+                }
+
+                ty::TyRef(..) => {
+                    PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
+                }
+
+                ty::TySlice(_) | ty::TyArray(..) => {
+                    PatternKind::Slice {
+                        prefix: pats.collect(),
+                        slice: None,
+                        suffix: vec![]
+                    }
+                }
+
+                _ => {
+                    match *ctor {
+                        ConstantValue(value) => PatternKind::Constant { value },
+                        _ => PatternKind::Wild,
+                    }
+                }
+            }
+        };
+
+        self.0.push(Pattern {
+            ty,
+            span: DUMMY_SP,
+            kind: Box::new(pat),
+        });
+
+        self
+    }
+}
+
+/// This determines the set of all possible constructors of a pattern matching
+/// values of type `left_ty`. For vectors, this would normally be an infinite set
+/// but is instead bounded by the maximum fixed length of slice patterns in
+/// the column of patterns being analyzed.
+///
+/// This intentionally does not list ConstantValue specializations for
+/// non-booleans, because we currently assume that there is always a
+/// "non-standard constant" that matches. See issue #12483.
+///
+/// We make sure to omit constructors that are statically impossible. eg for
+/// Option<!> we do not include Some(_) in the returned list of constructors.
+fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                                  pcx: PatternContext<'tcx>)
+                                  -> Vec<Constructor<'tcx>>
+{
+    debug!("all_constructors({:?})", pcx.ty);
+    match pcx.ty.sty {
+        ty::TyBool => {
+            [true, false].iter().map(|&b| {
+                ConstantValue(cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
+                    ty: cx.tcx.types.bool
+                }))
+            }).collect()
+        }
+        ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
+            let len = len.val.unwrap_u64();
+            if len != 0 && cx.is_uninhabited(sub_ty) {
+                vec![]
+            } else {
+                vec![Slice(len)]
+            }
+        }
+        // Treat arrays of a constant but unknown length like slices.
+        ty::TyArray(ref sub_ty, _) |
+        ty::TySlice(ref sub_ty) => {
+            if cx.is_uninhabited(sub_ty) {
+                vec![Slice(0)]
+            } else {
+                (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
+            }
+        }
+        ty::TyAdt(def, substs) if def.is_enum() => {
+            def.variants.iter()
+                .filter(|v| !cx.is_variant_uninhabited(v, substs))
+                .map(|v| Variant(v.did))
+                .collect()
+        }
+        _ => {
+            if cx.is_uninhabited(pcx.ty) {
+                vec![]
+            } else {
+                vec![Single]
+            }
+        }
+    }
+}
+
+fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
+    cx: &mut MatchCheckCtxt<'a, 'tcx>,
+    patterns: I) -> u64
+    where I: Iterator<Item=&'p Pattern<'tcx>>
+{
+    // The exhaustiveness-checking paper does not include any details on
+    // checking variable-length slice patterns. However, they are matched
+    // by an infinite collection of fixed-length array patterns.
+    //
+    // Checking the infinite set directly would take an infinite amount
+    // of time. However, it turns out that for each finite set of
+    // patterns `P`, all sufficiently large array lengths are equivalent:
+    //
+    // Each slice `s` with a "sufficiently-large" length `l â‰¥ L` that applies
+    // to exactly the subset `Pâ‚œ` of `P` can be transformed to a slice
+    // `sₘ` for each sufficiently-large length `m` that applies to exactly
+    // the same subset of `P`.
+    //
+    // Because of that, each witness for reachability-checking from one
+    // of the sufficiently-large lengths can be transformed to an
+    // equally-valid witness from any other length, so we only have
+    // to check slice lengths from the "minimal sufficiently-large length"
+    // and below.
+    //
+    // Note that the fact that there is a *single* `sₘ` for each `m`
+    // not depending on the specific pattern in `P` is important: if
+    // you look at the pair of patterns
+    //     `[true, ..]`
+    //     `[.., false]`
+    // Then any slice of length â‰¥1 that matches one of these two
+    // patterns can be  be trivially turned to a slice of any
+    // other length â‰¥1 that matches them and vice-versa - for
+    // but the slice from length 2 `[false, true]` that matches neither
+    // of these patterns can't be turned to a slice from length 1 that
+    // matches neither of these patterns, so we have to consider
+    // slices from length 2 there.
+    //
+    // Now, to see that that length exists and find it, observe that slice
+    // patterns are either "fixed-length" patterns (`[_, _, _]`) or
+    // "variable-length" patterns (`[_, .., _]`).
+    //
+    // For fixed-length patterns, all slices with lengths *longer* than
+    // the pattern's length have the same outcome (of not matching), so
+    // as long as `L` is greater than the pattern's length we can pick
+    // any `sₘ` from that length and get the same result.
+    //
+    // For variable-length patterns, the situation is more complicated,
+    // because as seen above the precise value of `sₘ` matters.
+    //
+    // However, for each variable-length pattern `p` with a prefix of length
+    // `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
+    // `slâ‚š` elements are examined.
+    //
+    // Therefore, as long as `L` is positive (to avoid concerns about empty
+    // types), all elements after the maximum prefix length and before
+    // the maximum suffix length are not examined by any variable-length
+    // pattern, and therefore can be added/removed without affecting
+    // them - creating equivalent patterns from any sufficiently-large
+    // length.
+    //
+    // Of course, if fixed-length patterns exist, we must be sure
+    // that our length is large enough to miss them all, so
+    // we can pick `L = max(FIXED_LEN+1 âˆª {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
+    //
+    // for example, with the above pair of patterns, all elements
+    // but the first and last can be added/removed, so any
+    // witness of length â‰¥2 (say, `[false, false, true]`) can be
+    // turned to a witness from any other length â‰¥2.
+
+    let mut max_prefix_len = 0;
+    let mut max_suffix_len = 0;
+    let mut max_fixed_len = 0;
+
+    for row in patterns {
+        match *row.kind {
+            PatternKind::Constant {
+                value: &ty::Const {
+                    val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
+                    ty,
+                }
+            } => {
+                let is_array_ptr = ty
+                    .builtin_deref(true, ty::NoPreference)
+                    .and_then(|t| t.ty.builtin_index())
+                    .map_or(false, |t| t == cx.tcx.types.u8);
+                if is_array_ptr {
+                    let alloc = cx.tcx
+                        .interpret_interner
+                        .get_alloc(ptr.alloc_id)
+                        .unwrap();
+                    max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+                }
+            }
+            PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
+                let fixed_len = prefix.len() as u64 + suffix.len() as u64;
+                max_fixed_len = cmp::max(max_fixed_len, fixed_len);
+            }
+            PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
+                max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
+                max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
+            }
+            _ => {}
+        }
+    }
+
+    cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
+}
+
+/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
+/// The algorithm from the paper has been modified to correctly handle empty
+/// types. The changes are:
+///   (0) We don't exit early if the pattern matrix has zero rows. We just
+///       continue to recurse over columns.
+///   (1) all_constructors will only return constructors that are statically
+///       possible. eg. it will only return Ok for Result<T, !>
+///
+/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
+/// to a set of such vectors `m` - this is defined as there being a set of
+/// inputs that will match `v` but not any of the sets in `m`.
+///
+/// All the patterns at each column of the `matrix ++ v` matrix must
+/// have the same type, except that wildcard (PatternKind::Wild) patterns
+/// with type TyErr are also allowed, even if the "type of the column"
+/// is not TyErr. That is used to represent private fields, as using their
+/// real type would assert that they are inhabited.
+///
+/// This is used both for reachability checking (if a pattern isn't useful in
+/// relation to preceding patterns, it is not reachable) and exhaustiveness
+/// checking (if a wildcard pattern is useful in relation to a matrix, the
+/// matrix isn't exhaustive).
+pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                                       matrix: &Matrix<'p, 'tcx>,
+                                       v: &[&'p Pattern<'tcx>],
+                                       witness: WitnessPreference)
+                                       -> Usefulness<'tcx> {
+    let &Matrix(ref rows) = matrix;
+    debug!("is_useful({:#?}, {:#?})", matrix, v);
+
+    // The base case. We are pattern-matching on () and the return value is
+    // based on whether our matrix has a row or not.
+    // NOTE: This could potentially be optimized by checking rows.is_empty()
+    // first and then, if v is non-empty, the return value is based on whether
+    // the type of the tuple we're checking is inhabited or not.
+    if v.is_empty() {
+        return if rows.is_empty() {
+            match witness {
+                ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
+                LeaveOutWitness => Useful,
+            }
+        } else {
+            NotUseful
+        }
+    };
+
+    assert!(rows.iter().all(|r| r.len() == v.len()));
+
+    let pcx = PatternContext {
+        // TyErr is used to represent the type of wildcard patterns matching
+        // against inaccessible (private) fields of structs, so that we won't
+        // be able to observe whether the types of the struct's fields are
+        // inhabited.
+        //
+        // If the field is truly inaccessible, then all the patterns
+        // matching against it must be wildcard patterns, so its type
+        // does not matter.
+        //
+        // However, if we are matching against non-wildcard patterns, we
+        // need to know the real type of the field so we can specialize
+        // against it. This primarily occurs through constants - they
+        // can include contents for fields that are inaccessible at the
+        // location of the match. In that case, the field's type is
+        // inhabited - by the constant - so we can just use it.
+        //
+        // FIXME: this might lead to "unstable" behavior with macro hygiene
+        // introducing uninhabited patterns for inaccessible fields. We
+        // need to figure out how to model that.
+        ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
+            .unwrap_or(v[0].ty),
+        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
+    };
+
+    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
+
+    if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
+        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.is_useful()).unwrap_or(NotUseful)
+    } else {
+        debug!("is_useful - expanding wildcard");
+
+        let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
+            pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
+        }).collect();
+        debug!("used_ctors = {:#?}", used_ctors);
+        let all_ctors = all_constructors(cx, pcx);
+        debug!("all_ctors = {:#?}", all_ctors);
+        let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
+            !used_ctors.contains(*c)
+        }).cloned().collect();
+
+        // `missing_ctors` is the set of constructors from the same type as the
+        // first column of `matrix` that are matched only by wildcard patterns
+        // from the first column.
+        //
+        // Therefore, if there is some pattern that is unmatched by `matrix`,
+        // it will still be unmatched if the first constructor is replaced by
+        // any of the constructors in `missing_ctors`
+        //
+        // However, if our scrutinee is *privately* an empty enum, we
+        // must treat it as though it had an "unknown" constructor (in
+        // that case, all other patterns obviously can't be variants)
+        // to avoid exposing its emptyness. See the `match_privately_empty`
+        // test for details.
+        //
+        // FIXME: currently the only way I know of something can
+        // be a privately-empty enum is when the never_type
+        // feature flag is not present, so this is only
+        // needed for that case.
+
+        let is_privately_empty =
+            all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+        let is_declared_nonexhaustive =
+            cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
+        debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
+               missing_ctors, is_privately_empty, is_declared_nonexhaustive);
+
+        // For privately empty and non-exhaustive enums, we work as if there were an "extra"
+        // `_` constructor for the type, so we can never match over all constructors.
+        let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
+
+        if missing_ctors.is_empty() && !is_non_exhaustive {
+            all_ctors.into_iter().map(|c| {
+                is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
+            }).find(|result| result.is_useful()).unwrap_or(NotUseful)
+        } else {
+            let matrix = rows.iter().filter_map(|r| {
+                if r[0].is_wildcard() {
+                    Some(r[1..].to_vec())
+                } else {
+                    None
+                }
+            }).collect();
+            match is_useful(cx, &matrix, &v[1..], witness) {
+                UsefulWithWitness(pats) => {
+                    let cx = &*cx;
+                    // In this case, there's at least one "free"
+                    // constructor that is only matched against by
+                    // wildcard patterns.
+                    //
+                    // There are 2 ways we can report a witness here.
+                    // Commonly, we can report all the "free"
+                    // constructors as witnesses, e.g. if we have:
+                    //
+                    // ```
+                    //     enum Direction { N, S, E, W }
+                    //     let Direction::N = ...;
+                    // ```
+                    //
+                    // we can report 3 witnesses: `S`, `E`, and `W`.
+                    //
+                    // However, there are 2 cases where we don't want
+                    // to do this and instead report a single `_` witness:
+                    //
+                    // 1) If the user is matching against a non-exhaustive
+                    // enum, there is no point in enumerating all possible
+                    // variants, because the user can't actually match
+                    // against them himself, e.g. in an example like:
+                    // ```
+                    //     let err: io::ErrorKind = ...;
+                    //     match err {
+                    //         io::ErrorKind::NotFound => {},
+                    //     }
+                    // ```
+                    // we don't want to show every possible IO error,
+                    // but instead have `_` as the witness (this is
+                    // actually *required* if the user specified *all*
+                    // IO errors, but is probably what we want in every
+                    // case).
+                    //
+                    // 2) If the user didn't actually specify a constructor
+                    // in this arm, e.g. in
+                    // ```
+                    //     let x: (Direction, Direction, bool) = ...;
+                    //     let (_, _, false) = x;
+                    // ```
+                    // we don't want to show all 16 possible witnesses
+                    // `(<direction-1>, <direction-2>, true)` - we are
+                    // satisfied with `(_, _, true)`. In this case,
+                    // `used_ctors` is empty.
+                    let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
+                        // All constructors are unused. Add wild patterns
+                        // rather than each individual constructor
+                        pats.into_iter().map(|mut witness| {
+                            witness.0.push(Pattern {
+                                ty: pcx.ty,
+                                span: DUMMY_SP,
+                                kind: box PatternKind::Wild,
+                            });
+                            witness
+                        }).collect()
+                    } else {
+                        pats.into_iter().flat_map(|witness| {
+                            missing_ctors.iter().map(move |ctor| {
+                                witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
+                            })
+                        }).collect()
+                    };
+                    UsefulWithWitness(new_witnesses)
+                }
+                result => result
+            }
+        }
+    }
+}
+
+fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
+    cx: &mut MatchCheckCtxt<'a, 'tcx>,
+    &Matrix(ref m): &Matrix<'p, 'tcx>,
+    v: &[&'p Pattern<'tcx>],
+    ctor: Constructor<'tcx>,
+    lty: Ty<'tcx>,
+    witness: WitnessPreference) -> Usefulness<'tcx>
+{
+    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
+    let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
+    let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
+        Pattern {
+            ty,
+            span: DUMMY_SP,
+            kind: box PatternKind::Wild,
+        }
+    }).collect();
+    let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
+    let matrix = Matrix(m.iter().flat_map(|r| {
+        specialize(cx, &r, &ctor, &wild_patterns)
+    }).collect());
+    match specialize(cx, v, &ctor, &wild_patterns) {
+        Some(v) => match is_useful(cx, &matrix, &v, witness) {
+            UsefulWithWitness(witnesses) => UsefulWithWitness(
+                witnesses.into_iter()
+                    .map(|witness| witness.apply_constructor(cx, &ctor, lty))
+                    .collect()
+            ),
+            result => result
+        },
+        None => NotUseful
+    }
+}
+
+/// Determines the constructors that the given pattern can be specialized to.
+///
+/// In most cases, there's only one constructor that a specific pattern
+/// represents, such as a specific enum variant or a specific literal value.
+/// Slice patterns, however, can match slices of different lengths. For instance,
+/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
+///
+/// Returns None in case of a catch-all, which can't be specialized.
+fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+                          pat: &Pattern<'tcx>,
+                          pcx: PatternContext)
+                          -> Option<Vec<Constructor<'tcx>>>
+{
+    match *pat.kind {
+        PatternKind::Binding { .. } | PatternKind::Wild =>
+            None,
+        PatternKind::Leaf { .. } | PatternKind::Deref { .. } =>
+            Some(vec![Single]),
+        PatternKind::Variant { adt_def, variant_index, .. } =>
+            Some(vec![Variant(adt_def.variants[variant_index].did)]),
+        PatternKind::Constant { value } =>
+            Some(vec![ConstantValue(value)]),
+        PatternKind::Range { lo, hi, end } =>
+            Some(vec![ConstantRange(lo, hi, end)]),
+        PatternKind::Array { .. } => match pcx.ty.sty {
+            ty::TyArray(_, length) => Some(vec![
+                Slice(length.val.unwrap_u64())
+            ]),
+            _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
+        },
+        PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
+            let pat_len = prefix.len() as u64 + suffix.len() as u64;
+            if slice.is_some() {
+                Some((pat_len..pcx.max_slice_length+1).map(Slice).collect())
+            } else {
+                Some(vec![Slice(pat_len)])
+            }
+        }
+    }
+}
+
+/// This computes the arity of a constructor. The arity of a constructor
+/// is how many subpattern patterns of that constructor should be expanded to.
+///
+/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
+/// A struct pattern's arity is the number of fields it contains, etc.
+fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
+    debug!("constructor_arity({:#?}, {:?})", ctor, ty);
+    match ty.sty {
+        ty::TyTuple(ref fs, _) => fs.len() as u64,
+        ty::TySlice(..) | ty::TyArray(..) => match *ctor {
+            Slice(length) => length,
+            ConstantValue(_) => 0,
+            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
+        },
+        ty::TyRef(..) => 1,
+        ty::TyAdt(adt, _) => {
+            adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
+        }
+        _ => 0
+    }
+}
+
+/// This computes the types of the sub patterns that a constructor should be
+/// expanded to.
+///
+/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
+fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
+                                             ctor: &Constructor,
+                                             ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
+{
+    debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
+    match ty.sty {
+        ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
+        ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
+            Slice(length) => (0..length).map(|_| ty).collect(),
+            ConstantValue(_) => vec![],
+            Single => vec![ty],
+            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
+        },
+        ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
+        ty::TyAdt(adt, substs) => {
+            if adt.is_box() {
+                // Use T as the sub pattern type of Box<T>.
+                vec![substs.type_at(0)]
+            } else {
+                if let ConstantValue(_) = *ctor {
+                    return vec![];
+                }
+                adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
+                    let is_visible = adt.is_enum()
+                        || field.vis.is_accessible_from(cx.module, cx.tcx);
+                    if is_visible {
+                        field.ty(cx.tcx, substs)
+                    } else {
+                        // Treat all non-visible fields as TyErr. They
+                        // can't appear in any other pattern from
+                        // this match (because they are private),
+                        // so their type does not matter - but
+                        // we don't want to know they are
+                        // uninhabited.
+                        cx.tcx.types.err
+                    }
+                }).collect()
+            }
+        }
+        _ => vec![],
+    }
+}
+
+fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
+                                    ctor: &Constructor,
+                                    prefix: &[Pattern],
+                                    slice: &Option<Pattern>,
+                                    suffix: &[Pattern])
+                                    -> Result<bool, ErrorReported> {
+    let data: &[u8] = match *ctor {
+        ConstantValue(&ty::Const { val: ConstVal::Value(
+            Value::ByVal(PrimVal::Ptr(ptr))
+        ), ty }) => {
+            let is_array_ptr = ty
+                .builtin_deref(true, ty::NoPreference)
+                .and_then(|t| t.ty.builtin_index())
+                .map_or(false, |t| t == tcx.types.u8);
+            assert!(is_array_ptr);
+            tcx
+                .interpret_interner
+                .get_alloc(ptr.alloc_id)
+                .unwrap()
+                .bytes
+                .as_ref()
+        }
+        _ => bug!()
+    };
+
+    let pat_len = prefix.len() + suffix.len();
+    if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
+        return Ok(false);
+    }
+
+    for (ch, pat) in
+        data[..prefix.len()].iter().zip(prefix).chain(
+            data[data.len()-suffix.len()..].iter().zip(suffix))
+    {
+        match pat.kind {
+            box PatternKind::Constant { value } => match value.val {
+                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
+                    assert_eq!(b as u8 as u128, b);
+                    if b as u8 != *ch {
+                        return Ok(false);
+                    }
+                }
+                _ => span_bug!(pat.span, "bad const u8 {:?}", value)
+            },
+            _ => {}
+        }
+    }
+
+    Ok(true)
+}
+
+fn constructor_covered_by_range(ctor: &Constructor,
+                                from: &ConstVal, to: &ConstVal,
+                                end: RangeEnd,
+                                ty: Ty)
+                                -> Result<bool, ErrorReported> {
+    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
+    let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
+        .map(|res| res != Ordering::Less);
+    let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
+    macro_rules! some_or_ok {
+        ($e:expr) => {
+            match $e {
+                Some(to) => to,
+                None => return Ok(false), // not char or int
+            }
+        };
+    }
+    match *ctor {
+        ConstantValue(value) => {
+            let to = some_or_ok!(cmp_to(&value.val));
+            let end = (to == Ordering::Less) ||
+                      (end == RangeEnd::Included && to == Ordering::Equal);
+            Ok(some_or_ok!(cmp_from(&value.val)) && end)
+        },
+        ConstantRange(from, to, RangeEnd::Included) => {
+            let to = some_or_ok!(cmp_to(&to.val));
+            let end = (to == Ordering::Less) ||
+                      (end == RangeEnd::Included && to == Ordering::Equal);
+            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+        },
+        ConstantRange(from, to, RangeEnd::Excluded) => {
+            let to = some_or_ok!(cmp_to(&to.val));
+            let end = (to == Ordering::Less) ||
+                      (end == RangeEnd::Excluded && to == Ordering::Equal);
+            Ok(some_or_ok!(cmp_from(&from.val)) && end)
+        }
+        Variant(_) |
+        Single => Ok(true),
+        _ => bug!(),
+    }
+}
+
+fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
+    subpatterns: &'p [FieldPattern<'tcx>],
+    wild_patterns: &[&'p Pattern<'tcx>])
+    -> Vec<&'p Pattern<'tcx>>
+{
+    let mut result = wild_patterns.to_owned();
+
+    for subpat in subpatterns {
+        result[subpat.field.index()] = &subpat.pattern;
+    }
+
+    debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
+    result
+}
+
+/// This is the main specialization step. It expands the first pattern in the given row
+/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
+/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
+///
+/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple
+/// different patterns.
+/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
+/// fields filled with wild patterns.
+fn specialize<'p, 'a: 'p, 'tcx: 'a>(
+    cx: &mut MatchCheckCtxt<'a, 'tcx>,
+    r: &[&'p Pattern<'tcx>],
+    constructor: &Constructor<'tcx>,
+    wild_patterns: &[&'p Pattern<'tcx>])
+    -> Option<Vec<&'p Pattern<'tcx>>>
+{
+    let pat = &r[0];
+
+    let head: Option<Vec<&Pattern>> = match *pat.kind {
+        PatternKind::Binding { .. } | PatternKind::Wild => {
+            Some(wild_patterns.to_owned())
+        },
+
+        PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
+            let ref variant = adt_def.variants[variant_index];
+            if *constructor == Variant(variant.did) {
+                Some(patterns_for_variant(subpatterns, wild_patterns))
+            } else {
+                None
+            }
+        }
+
+        PatternKind::Leaf { ref subpatterns } => {
+            Some(patterns_for_variant(subpatterns, wild_patterns))
+        }
+        PatternKind::Deref { ref subpattern } => {
+            Some(vec![subpattern])
+        }
+
+        PatternKind::Constant { value } => {
+            match *constructor {
+                Slice(..) => match value.val {
+                    ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+                        let is_array_ptr = value.ty
+                            .builtin_deref(true, ty::NoPreference)
+                            .and_then(|t| t.ty.builtin_index())
+                            .map_or(false, |t| t == cx.tcx.types.u8);
+                        assert!(is_array_ptr);
+                        let data_len = cx.tcx
+                            .interpret_interner
+                            .get_alloc(ptr.alloc_id)
+                            .unwrap()
+                            .bytes
+                            .len();
+                        if wild_patterns.len() == data_len {
+                            Some(cx.lower_byte_str_pattern(pat))
+                        } else {
+                            None
+                        }
+                    }
+                    _ => span_bug!(pat.span,
+                        "unexpected const-val {:?} with ctor {:?}", value, constructor)
+                },
+                _ => {
+                    match constructor_covered_by_range(
+                        constructor, &value.val, &value.val, RangeEnd::Included,
+                        value.ty,
+                            ) {
+                        Ok(true) => Some(vec![]),
+                        Ok(false) => None,
+                        Err(ErrorReported) => None,
+                    }
+                }
+            }
+        }
+
+        PatternKind::Range { lo, hi, ref end } => {
+            match constructor_covered_by_range(
+                constructor, &lo.val, &hi.val, end.clone(), lo.ty,
+            ) {
+                Ok(true) => Some(vec![]),
+                Ok(false) => None,
+                Err(ErrorReported) => None,
+            }
+        }
+
+        PatternKind::Array { ref prefix, ref slice, ref suffix } |
+        PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
+            match *constructor {
+                Slice(..) => {
+                    let pat_len = prefix.len() + suffix.len();
+                    if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) {
+                        if slice_count == 0 || slice.is_some() {
+                            Some(
+                                prefix.iter().chain(
+                                wild_patterns.iter().map(|p| *p)
+                                                    .skip(prefix.len())
+                                                    .take(slice_count)
+                                                    .chain(
+                                suffix.iter()
+                            )).collect())
+                        } else {
+                            None
+                        }
+                    } else {
+                        None
+                    }
+                }
+                ConstantValue(..) => {
+                    match slice_pat_covered_by_constructor(
+                        cx.tcx, pat.span, constructor, prefix, slice, suffix
+                            ) {
+                        Ok(true) => Some(vec![]),
+                        Ok(false) => None,
+                        Err(ErrorReported) => None
+                    }
+                }
+                _ => span_bug!(pat.span,
+                    "unexpected ctor {:?} for slice pat", constructor)
+            }
+        }
+    };
+    debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
+
+    head.map(|mut head| {
+        head.extend_from_slice(&r[1 ..]);
+        head
+    })
+}
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
new file mode 100644 (file)
index 0000000..69ed4e6
--- /dev/null
@@ -0,0 +1,646 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
+use super::_match::Usefulness::*;
+use super::_match::WitnessPreference::*;
+
+use super::{Pattern, PatternContext, PatternError, PatternKind};
+
+use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
+use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
+use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::mem_categorization::{cmt};
+use rustc::middle::region;
+use rustc::session::Session;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
+use rustc::lint;
+use rustc_errors::DiagnosticBuilder;
+use rustc::util::common::ErrorReported;
+
+use rustc::hir::def::*;
+use rustc::hir::def_id::DefId;
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::hir::{self, Pat, PatKind};
+
+use std::slice;
+
+use syntax::ast;
+use syntax::ptr::P;
+use syntax_pos::{Span, DUMMY_SP};
+
+struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
+
+impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
+    }
+
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        intravisit::walk_body(self, body);
+        let def_id = self.tcx.hir.body_owner_def_id(body.id());
+        let _ = self.tcx.check_match(def_id);
+    }
+}
+
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.hir.krate().visit_all_item_likes(&mut OuterVisitor { tcx: tcx }.as_deep_visitor());
+    tcx.sess.abort_if_errors();
+}
+
+pub(crate) fn check_match<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+) -> Result<(), ErrorReported> {
+    let body_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+        tcx.hir.body_owned_by(id)
+    } else {
+        return Ok(());
+    };
+
+    tcx.sess.track_errors(|| {
+        MatchVisitor {
+            tcx,
+            tables: tcx.body_tables(body_id),
+            region_scope_tree: &tcx.region_scope_tree(def_id),
+            param_env: tcx.param_env(def_id),
+            identity_substs: Substs::identity_for_item(tcx, def_id),
+        }.visit_body(tcx.hir.body(body_id));
+    })
+}
+
+fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
+    struct_span_err!(sess, sp, E0004, "{}", &error_message)
+}
+
+struct MatchVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::TypeckTables<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    identity_substs: &'tcx Substs<'tcx>,
+    region_scope_tree: &'a region::ScopeTree,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
+        intravisit::walk_expr(self, ex);
+
+        match ex.node {
+            hir::ExprMatch(ref scrut, ref arms, source) => {
+                self.check_match(scrut, arms, source);
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_local(&mut self, loc: &'tcx hir::Local) {
+        intravisit::walk_local(self, loc);
+
+        self.check_irrefutable(&loc.pat, match loc.source {
+            hir::LocalSource::Normal => "local binding",
+            hir::LocalSource::ForLoopDesugar => "`for` loop binding",
+        });
+
+        // Check legality of move bindings and `@` patterns.
+        self.check_patterns(false, slice::from_ref(&loc.pat));
+    }
+
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        intravisit::walk_body(self, body);
+
+        for arg in &body.arguments {
+            self.check_irrefutable(&arg.pat, "function argument");
+            self.check_patterns(false, slice::from_ref(&arg.pat));
+        }
+    }
+}
+
+
+impl<'a, 'tcx> PatternContext<'a, 'tcx> {
+    fn report_inlining_errors(&self, pat_span: Span) {
+        for error in &self.errors {
+            match *error {
+                PatternError::StaticInPattern(span) => {
+                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                }
+                PatternError::AssociatedConstInPattern(span) => {
+                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
+                }
+                PatternError::FloatBug => {
+                    // FIXME(#31407) this is only necessary because float parsing is buggy
+                    ::rustc::middle::const_val::struct_error(
+                        self.tcx, pat_span,
+                        "could not evaluate float literal (see issue #31407)",
+                    ).emit();
+                }
+                PatternError::NonConstPath(span) => {
+                    ::rustc::middle::const_val::struct_error(
+                        self.tcx, span,
+                        "runtime values cannot be referenced in patterns",
+                    ).emit();
+                }
+            }
+        }
+    }
+
+    fn span_e0158(&self, span: Span, text: &str) {
+        span_err!(self.tcx.sess, span, E0158, "{}", text)
+    }
+}
+
+impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
+    fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
+        check_legality_of_move_bindings(self, has_guard, pats);
+        for pat in pats {
+            check_legality_of_bindings_in_at_patterns(self, pat);
+        }
+    }
+
+    fn check_match(
+        &self,
+        scrut: &hir::Expr,
+        arms: &'tcx [hir::Arm],
+        source: hir::MatchSource)
+    {
+        for arm in arms {
+            // First, check legality of move bindings.
+            self.check_patterns(arm.guard.is_some(), &arm.pats);
+
+            // Second, if there is a guard on each arm, make sure it isn't
+            // assigning or borrowing anything mutably.
+            if let Some(ref guard) = arm.guard {
+                check_for_mutation_in_guard(self, &guard);
+            }
+
+            // Third, perform some lints.
+            for pat in &arm.pats {
+                check_for_bindings_named_the_same_as_variants(self, pat);
+            }
+        }
+
+        let module = self.tcx.hir.get_module_parent(scrut.id);
+        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
+            let mut have_errors = false;
+
+            let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
+                arm.pats.iter().map(|pat| {
+                    let mut patcx = PatternContext::new(self.tcx,
+                                                        self.param_env.and(self.identity_substs),
+                                                        self.tables);
+                    let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
+                    if !patcx.errors.is_empty() {
+                        patcx.report_inlining_errors(pat.span);
+                        have_errors = true;
+                    }
+                    (pattern, &**pat)
+                }).collect(),
+                arm.guard.as_ref().map(|e| &**e)
+            )).collect();
+
+            // Bail out early if inlining failed.
+            if have_errors {
+                return;
+            }
+
+            // Fourth, check for unreachable arms.
+            check_arms(cx, &inlined_arms, source);
+
+            // Then, if the match has no arms, check whether the scrutinee
+            // is uninhabited.
+            let pat_ty = self.tables.node_id_to_type(scrut.hir_id);
+            let module = self.tcx.hir.get_module_parent(scrut.id);
+            if inlined_arms.is_empty() {
+                let scrutinee_is_uninhabited = if self.tcx.features().never_type {
+                    self.tcx.is_ty_uninhabited_from(module, pat_ty)
+                } else {
+                    self.conservative_is_uninhabited(pat_ty)
+                };
+                if !scrutinee_is_uninhabited {
+                    // We know the type is inhabited, so this must be wrong
+                    let mut err = create_e0004(self.tcx.sess, scrut.span,
+                                               format!("non-exhaustive patterns: type {} \
+                                                        is non-empty",
+                                                       pat_ty));
+                    span_help!(&mut err, scrut.span,
+                               "Please ensure that all possible cases are being handled; \
+                                possibly adding wildcards or more match arms.");
+                    err.emit();
+                }
+                // If the type *is* uninhabited, it's vacuously exhaustive
+                return;
+            }
+
+            let matrix: Matrix = inlined_arms
+                .iter()
+                .filter(|&&(_, guard)| guard.is_none())
+                .flat_map(|arm| &arm.0)
+                .map(|pat| vec![pat.0])
+                .collect();
+            let scrut_ty = self.tables.node_id_to_type(scrut.hir_id);
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
+        })
+    }
+
+    fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
+        // "rustc-1.0-style" uncontentious uninhabitableness check
+        match scrutinee_ty.sty {
+            ty::TyNever => true,
+            ty::TyAdt(def, _) => def.variants.is_empty(),
+            _ => false
+        }
+    }
+
+    fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
+        let module = self.tcx.hir.get_module_parent(pat.id);
+        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
+            let mut patcx = PatternContext::new(self.tcx,
+                                                self.param_env.and(self.identity_substs),
+                                                self.tables);
+            let pattern = patcx.lower_pattern(pat);
+            let pattern_ty = pattern.ty;
+            let pats : Matrix = vec![vec![
+                expand_pattern(cx, pattern)
+            ]].into_iter().collect();
+
+            let wild_pattern = Pattern {
+                ty: pattern_ty,
+                span: DUMMY_SP,
+                kind: box PatternKind::Wild,
+            };
+            let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
+                UsefulWithWitness(witness) => witness,
+                NotUseful => return,
+                Useful => bug!()
+            };
+
+            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",
+                origin, pattern_string
+            );
+            let label_msg = match pat.node {
+                PatKind::Path(hir::QPath::Resolved(None, ref path))
+                        if path.segments.len() == 1 && path.segments[0].parameters.is_none() => {
+                    format!("interpreted as a {} pattern, not new variable", path.def.kind_name())
+                }
+                _ => format!("pattern `{}` not covered", pattern_string),
+            };
+            diag.span_label(pat.span, label_msg);
+            diag.emit();
+        });
+    }
+}
+
+fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
+    pat.walk(|p| {
+        if let PatKind::Binding(_, _, name, None) = p.node {
+            let bm = *cx.tables
+                        .pat_binding_modes()
+                        .get(p.hir_id)
+                        .expect("missing binding mode");
+
+            if bm != ty::BindByValue(hir::MutImmutable) {
+                // Nothing to check.
+                return true;
+            }
+            let pat_ty = cx.tables.pat_ty(p);
+            if let ty::TyAdt(edef, _) = pat_ty.sty {
+                if edef.is_enum() && edef.variants.iter().any(|variant| {
+                    variant.name == name.node && variant.ctor_kind == CtorKind::Const
+                }) {
+                    let ty_path = cx.tcx.item_path_str(edef.did);
+                    let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
+                        "pattern binding `{}` is named the same as one \
+                         of the variants of the type `{}`",
+                        name.node, ty_path);
+                    help!(err,
+                        "if you meant to match on a variant, \
+                        consider making the path in the pattern qualified: `{}::{}`",
+                        ty_path, name.node);
+                    err.emit();
+                }
+            }
+        }
+        true
+    });
+}
+
+/// Checks for common cases of "catchall" patterns that may not be intended as such.
+fn pat_is_catchall(pat: &Pat) -> bool {
+    match pat.node {
+        PatKind::Binding(.., None) => true,
+        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
+        PatKind::Ref(ref s, _) => pat_is_catchall(s),
+        PatKind::Tuple(ref v, _) => v.iter().all(|p| {
+            pat_is_catchall(&p)
+        }),
+        _ => false
+    }
+}
+
+// Check for unreachable patterns
+fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                        arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
+                        source: hir::MatchSource)
+{
+    let mut seen = Matrix::empty();
+    let mut catchall = None;
+    let mut printed_if_let_err = false;
+    for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
+        for &(pat, hir_pat) in pats {
+            let v = vec![pat];
+
+            match is_useful(cx, &seen, &v, LeaveOutWitness) {
+                NotUseful => {
+                    match source {
+                        hir::MatchSource::IfLetDesugar { .. } => {
+                            if printed_if_let_err {
+                                // we already printed an irrefutable if-let pattern error.
+                                // We don't want two, that's just confusing.
+                            } else {
+                                // find the first arm pattern so we can use its span
+                                let &(ref first_arm_pats, _) = &arms[0];
+                                let first_pat = &first_arm_pats[0];
+                                let span = first_pat.0.span;
+                                struct_span_err!(cx.tcx.sess, span, E0162,
+                                                "irrefutable if-let pattern")
+                                    .span_label(span, "irrefutable pattern")
+                                    .emit();
+                                printed_if_let_err = true;
+                            }
+                        },
+
+                        hir::MatchSource::WhileLetDesugar => {
+                            // find the first arm pattern so we can use its span
+                            let &(ref first_arm_pats, _) = &arms[0];
+                            let first_pat = &first_arm_pats[0];
+                            let span = first_pat.0.span;
+
+                            // check which arm we're on.
+                            match arm_index {
+                                // The arm with the user-specified pattern.
+                                0 => {
+                                    cx.tcx.lint_node(
+                                            lint::builtin::UNREACHABLE_PATTERNS,
+                                        hir_pat.id, pat.span,
+                                        "unreachable pattern");
+                                },
+                                // The arm with the wildcard pattern.
+                                1 => {
+                                    struct_span_err!(cx.tcx.sess, span, E0165,
+                                                     "irrefutable while-let pattern")
+                                        .span_label(span, "irrefutable pattern")
+                                        .emit();
+                                },
+                                _ => bug!(),
+                            }
+                        },
+
+                        hir::MatchSource::ForLoopDesugar |
+                        hir::MatchSource::Normal => {
+                            let mut err = cx.tcx.struct_span_lint_node(
+                                lint::builtin::UNREACHABLE_PATTERNS,
+                                hir_pat.id,
+                                pat.span,
+                                "unreachable pattern",
+                            );
+                            // if we had a catchall pattern, hint at that
+                            if let Some(catchall) = catchall {
+                                err.span_label(pat.span, "unreachable pattern");
+                                err.span_label(catchall, "matches any value");
+                            }
+                            err.emit();
+                        },
+
+                        // Unreachable patterns in try expressions occur when one of the arms
+                        // are an uninhabited type. Which is OK.
+                        hir::MatchSource::TryDesugar => {}
+                    }
+                }
+                Useful => (),
+                UsefulWithWitness(_) => bug!()
+            }
+            if guard.is_none() {
+                seen.push(v);
+                if catchall.is_none() && pat_is_catchall(hir_pat) {
+                    catchall = Some(pat.span);
+                }
+            }
+        }
+    }
+}
+
+fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
+                              scrut_ty: Ty<'tcx>,
+                              sp: Span,
+                              matrix: &Matrix<'a, 'tcx>) {
+    let wild_pattern = Pattern {
+        ty: scrut_ty,
+        span: DUMMY_SP,
+        kind: box PatternKind::Wild,
+    };
+    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
+        UsefulWithWitness(pats) => {
+            let witnesses = if pats.is_empty() {
+                vec![&wild_pattern]
+            } else {
+                pats.iter().map(|w| w.single_pattern()).collect()
+            };
+
+            const LIMIT: usize = 3;
+            let joined_patterns = match witnesses.len() {
+                0 => bug!(),
+                1 => format!("`{}`", witnesses[0]),
+                2...LIMIT => {
+                    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) = 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 witnesses.len() {
+                1 => format!("pattern {} not covered", joined_patterns),
+                _ => format!("patterns {} not covered", joined_patterns)
+            };
+            create_e0004(cx.tcx.sess, sp,
+                            format!("non-exhaustive patterns: {} not covered",
+                                    joined_patterns))
+                .span_label(sp, label_text)
+                .emit();
+        }
+        NotUseful => {
+            // This is good, wildcard pattern isn't reachable
+        },
+        _ => bug!()
+    }
+}
+
+// Legality of move bindings checking
+fn check_legality_of_move_bindings(cx: &MatchVisitor,
+                                   has_guard: bool,
+                                   pats: &[P<Pat>]) {
+    let mut by_ref_span = None;
+    for pat in pats {
+        pat.each_binding(|_, id, span, _path| {
+            let hir_id = cx.tcx.hir.node_to_hir_id(id);
+            let bm = *cx.tables
+                        .pat_binding_modes()
+                        .get(hir_id)
+                        .expect("missing binding mode");
+            if let ty::BindByReference(..) = bm {
+                by_ref_span = Some(span);
+            }
+        })
+    }
+
+    let check_move = |p: &Pat, sub: Option<&Pat>| {
+        // check legality of moving out of the enum
+
+        // x @ Foo(..) is legal, but x @ Foo(y) isn't.
+        if sub.map_or(false, |p| p.contains_bindings()) {
+            struct_span_err!(cx.tcx.sess, p.span, E0007,
+                             "cannot bind by-move with sub-bindings")
+                .span_label(p.span, "binds an already bound by-move value by moving it")
+                .emit();
+        } else if has_guard {
+            struct_span_err!(cx.tcx.sess, p.span, E0008,
+                      "cannot bind by-move into a pattern guard")
+                .span_label(p.span, "moves value into pattern guard")
+                .emit();
+        } else if by_ref_span.is_some() {
+            struct_span_err!(cx.tcx.sess, p.span, E0009,
+                            "cannot bind by-move and by-ref in the same pattern")
+                    .span_label(p.span, "by-move pattern here")
+                    .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
+                    .emit();
+        }
+    };
+
+    for pat in pats {
+        pat.walk(|p| {
+            if let PatKind::Binding(_, _, _, ref sub) = p.node {
+                let bm = *cx.tables
+                            .pat_binding_modes()
+                            .get(p.hir_id)
+                            .expect("missing binding mode");
+                match bm {
+                    ty::BindByValue(..) => {
+                        let pat_ty = cx.tables.node_id_to_type(p.hir_id);
+                        if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
+                            check_move(p, sub.as_ref().map(|p| &**p));
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            true
+        });
+    }
+}
+
+/// Ensures that a pattern guard doesn't borrow by mutable reference or
+/// assign.
+///
+/// FIXME: this should be done by borrowck.
+fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
+    let mut checker = MutationChecker {
+        cx,
+    };
+    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
+        .walk_expr(guard);
+}
+
+struct MutationChecker<'a, 'tcx: 'a> {
+    cx: &'a MatchVisitor<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
+    fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
+    fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {}
+    fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
+    fn borrow(&mut self,
+              _: ast::NodeId,
+              span: Span,
+              _: cmt,
+              _: ty::Region<'tcx>,
+              kind:ty:: BorrowKind,
+              _: LoanCause) {
+        match kind {
+            ty::MutBorrow => {
+                struct_span_err!(self.cx.tcx.sess, span, E0301,
+                          "cannot mutably borrow in a pattern guard")
+                    .span_label(span, "borrowed mutably in pattern guard")
+                    .emit();
+            }
+            ty::ImmBorrow | ty::UniqueImmBorrow => {}
+        }
+    }
+    fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
+    fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) {
+        match mode {
+            MutateMode::JustWrite | MutateMode::WriteAndRead => {
+                struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
+                    .span_label(span, "assignment in pattern guard")
+                    .emit();
+            }
+            MutateMode::Init => {}
+        }
+    }
+}
+
+/// Forbids bindings in `@` patterns. This is necessary for memory safety,
+/// because of the way rvalues are handled in the borrow check. (See issue
+/// #14587.)
+fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor, pat: &Pat) {
+    AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
+}
+
+struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
+    cx: &'a MatchVisitor<'b, 'tcx>,
+    bindings_allowed: bool
+}
+
+impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_pat(&mut self, pat: &Pat) {
+        match pat.node {
+            PatKind::Binding(.., ref subpat) => {
+                if !self.bindings_allowed {
+                    struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
+                                     "pattern bindings are not allowed after an `@`")
+                        .span_label(pat.span,  "not allowed after `@`")
+                        .emit();
+                }
+
+                if subpat.is_some() {
+                    let bindings_were_allowed = self.bindings_allowed;
+                    self.bindings_allowed = false;
+                    intravisit::walk_pat(self, pat);
+                    self.bindings_allowed = bindings_were_allowed;
+                }
+            }
+            _ => intravisit::walk_pat(self, pat),
+        }
+    }
+}
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
new file mode 100644 (file)
index 0000000..1141425
--- /dev/null
@@ -0,0 +1,1186 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Code to validate patterns/matches
+
+mod _match;
+mod check_match;
+
+pub use self::check_match::check_crate;
+pub(crate) use self::check_match::check_match;
+
+use interpret::{const_val_field, const_discr};
+
+use rustc::middle::const_val::ConstVal;
+use rustc::mir::{Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::subst::{Substs, Kind};
+use rustc::hir::{self, PatKind, RangeEnd};
+use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::pat_util::EnumerateAndAdjustIterator;
+
+use rustc_data_structures::indexed_vec::Idx;
+use rustc_const_math::ConstFloat;
+
+use std::cmp::Ordering;
+use std::fmt;
+use syntax::ast;
+use syntax::ptr::P;
+use syntax_pos::Span;
+
+#[derive(Clone, Debug)]
+pub enum PatternError {
+    StaticInPattern(Span),
+    FloatBug,
+    NonConstPath(Span),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum BindingMode<'tcx> {
+    ByValue,
+    ByRef(Region<'tcx>, BorrowKind),
+}
+
+#[derive(Clone, Debug)]
+pub struct FieldPattern<'tcx> {
+    pub field: Field,
+    pub pattern: Pattern<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Pattern<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub span: Span,
+    pub kind: Box<PatternKind<'tcx>>,
+}
+
+#[derive(Clone, Debug)]
+pub enum PatternKind<'tcx> {
+    Wild,
+
+    /// x, ref x, x @ P, etc
+    Binding {
+        mutability: Mutability,
+        name: ast::Name,
+        mode: BindingMode<'tcx>,
+        var: ast::NodeId,
+        ty: Ty<'tcx>,
+        subpattern: Option<Pattern<'tcx>>,
+    },
+
+    /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
+    Variant {
+        adt_def: &'tcx AdtDef,
+        substs: &'tcx Substs<'tcx>,
+        variant_index: usize,
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    },
+
+    /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
+    Leaf {
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    },
+
+    /// box P, &P, &mut P, etc
+    Deref {
+        subpattern: Pattern<'tcx>,
+    },
+
+    Constant {
+        value: &'tcx ty::Const<'tcx>,
+    },
+
+    Range {
+        lo: &'tcx ty::Const<'tcx>,
+        hi: &'tcx ty::Const<'tcx>,
+        end: RangeEnd,
+    },
+
+    /// matches against a slice, checking the length and extracting elements.
+    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+    /// e.g. `&[ref xs..]`.
+    Slice {
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>,
+    },
+
+    /// fixed match against an array, irrefutable
+    Array {
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>,
+    },
+}
+
+fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
+    match value.val {
+        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+        ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
+    }
+}
+
+fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
+    use rustc::ty::TypeVariants::*;
+    match (value, &ty.sty) {
+        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
+        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
+            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
+        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
+    }
+}
+
+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 {
+                        if !adt.is_enum() {
+                            Some(&adt.variants[0])
+                        } else {
+                            None
+                        }
+                    } 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::TyAdt(def, _) if def.is_box() => 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 { value } => {
+                print_const_val(value, f)
+            }
+            PatternKind::Range { lo, hi, end } => {
+                print_const_val(lo, f)?;
+                match end {
+                    RangeEnd::Included => write!(f, "...")?,
+                    RangeEnd::Excluded => 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, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
+    pub tables: &'a ty::TypeckTables<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
+    pub errors: Vec<PatternError>,
+}
+
+impl<'a, 'tcx> Pattern<'tcx> {
+    pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
+                    tables: &'a ty::TypeckTables<'tcx>,
+                    pat: &'tcx hir::Pat) -> Self {
+        let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
+        let result = pcx.lower_pattern(pat);
+        if !pcx.errors.is_empty() {
+            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
+            tcx.sess.delay_span_bug(pat.span, &msg);
+        }
+        debug!("Pattern::from_hir({:?}) = {:?}", pat, result);
+        result
+    }
+}
+
+impl<'a, 'tcx> PatternContext<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
+               tables: &'a ty::TypeckTables<'tcx>) -> Self {
+        PatternContext {
+            tcx,
+            param_env: param_env_and_substs.param_env,
+            tables,
+            substs: param_env_and_substs.value,
+            errors: vec![]
+        }
+    }
+
+    pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
+        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
+        // pattern has the type that results *after* dereferencing. For example, in this code:
+        //
+        // ```
+        // match &&Some(0i32) {
+        //     Some(n) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
+        // determined in rustc_typeck::check::match). The adjustments would be
+        //
+        // `vec![&&Option<i32>, &Option<i32>]`.
+        //
+        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
+        // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the
+        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
+        // gets the least-dereferenced type).
+        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
+        self.tables
+            .pat_adjustments()
+            .get(pat.hir_id)
+            .unwrap_or(&vec![])
+            .iter()
+            .rev()
+            .fold(unadjusted_pat, |pat, ref_ty| {
+                    debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
+                    Pattern {
+                        span: pat.span,
+                        ty: ref_ty,
+                        kind: Box::new(PatternKind::Deref { subpattern: pat }),
+                    }
+                },
+            )
+    }
+
+    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
+        let mut ty = self.tables.node_id_to_type(pat.hir_id);
+
+        let kind = match pat.node {
+            PatKind::Wild => PatternKind::Wild,
+
+            PatKind::Lit(ref value) => self.lower_lit(value),
+
+            PatKind::Range(ref lo_expr, ref hi_expr, end) => {
+                match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
+                    (PatternKind::Constant { value: lo },
+                     PatternKind::Constant { value: hi }) => {
+                        use std::cmp::Ordering;
+                        match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
+                            (RangeEnd::Excluded, Ordering::Less) => {},
+                            (RangeEnd::Excluded, _) => span_err!(
+                                self.tcx.sess,
+                                lo_expr.span,
+                                E0579,
+                                "lower range bound must be less than upper",
+                            ),
+                            (RangeEnd::Included, Ordering::Greater) => {
+                                struct_span_err!(self.tcx.sess, lo_expr.span, E0030,
+                                    "lower range bound must be less than or equal to upper")
+                                    .span_label(lo_expr.span, "lower bound larger than upper bound")
+                                    .emit();
+                            },
+                            (RangeEnd::Included, _) => {}
+                        }
+                        PatternKind::Range { lo, hi, end }
+                    }
+                    _ => PatternKind::Wild
+                }
+            }
+
+            PatKind::Path(ref qpath) => {
+                return self.lower_path(qpath, pat.hir_id, pat.span);
+            }
+
+            PatKind::Ref(ref subpattern, _) |
+            PatKind::Box(ref subpattern) => {
+                PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
+            }
+
+            PatKind::Slice(ref prefix, ref slice, ref suffix) => {
+                let ty = self.tables.node_id_to_type(pat.hir_id);
+                match ty.sty {
+                    ty::TyRef(_, mt) =>
+                        PatternKind::Deref {
+                            subpattern: Pattern {
+                                ty: mt.ty,
+                                span: pat.span,
+                                kind: Box::new(self.slice_or_array_pattern(
+                                    pat.span, mt.ty, prefix, slice, suffix))
+                            },
+                        },
+
+                    ty::TySlice(..) |
+                    ty::TyArray(..) =>
+                        self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
+
+                    ref sty =>
+                        span_bug!(
+                            pat.span,
+                            "unexpanded type for vector pattern: {:?}",
+                            sty),
+                }
+            }
+
+            PatKind::Tuple(ref subpatterns, ddpos) => {
+                let ty = self.tables.node_id_to_type(pat.hir_id);
+                match ty.sty {
+                    ty::TyTuple(ref tys, _) => {
+                        let subpatterns =
+                            subpatterns.iter()
+                                       .enumerate_and_adjust(tys.len(), ddpos)
+                                       .map(|(i, subpattern)| FieldPattern {
+                                            field: Field::new(i),
+                                            pattern: self.lower_pattern(subpattern)
+                                       })
+                                       .collect();
+
+                        PatternKind::Leaf { subpatterns: subpatterns }
+                    }
+
+                    ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
+                }
+            }
+
+            PatKind::Binding(_, id, ref ident, ref sub) => {
+                let var_ty = self.tables.node_id_to_type(pat.hir_id);
+                let region = match var_ty.sty {
+                    ty::TyRef(r, _) => Some(r),
+                    _ => None,
+                };
+                let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
+                                                         .expect("missing binding mode");
+                let (mutability, mode) = match bm {
+                    ty::BindByValue(hir::MutMutable) =>
+                        (Mutability::Mut, BindingMode::ByValue),
+                    ty::BindByValue(hir::MutImmutable) =>
+                        (Mutability::Not, BindingMode::ByValue),
+                    ty::BindByReference(hir::MutMutable) =>
+                        (Mutability::Not, BindingMode::ByRef(
+                            region.unwrap(), BorrowKind::Mut)),
+                    ty::BindByReference(hir::MutImmutable) =>
+                        (Mutability::Not, BindingMode::ByRef(
+                            region.unwrap(), BorrowKind::Shared)),
+                };
+
+                // A ref x pattern is the same node used for x, and as such it has
+                // x's type, which is &T, where we want T (the type being matched).
+                if let ty::BindByReference(_) = bm {
+                    if let ty::TyRef(_, mt) = ty.sty {
+                        ty = mt.ty;
+                    } else {
+                        bug!("`ref {}` has wrong type {}", ident.node, ty);
+                    }
+                }
+
+                PatternKind::Binding {
+                    mutability,
+                    mode,
+                    name: ident.node,
+                    var: id,
+                    ty: var_ty,
+                    subpattern: self.lower_opt_pattern(sub),
+                }
+            }
+
+            PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
+                let def = self.tables.qpath_def(qpath, pat.hir_id);
+                let adt_def = match ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                        subpatterns.iter()
+                                   .enumerate_and_adjust(variant_def.fields.len(), ddpos)
+                                   .map(|(i, field)| FieldPattern {
+                                       field: Field::new(i),
+                                       pattern: self.lower_pattern(field),
+                                   })
+                                   .collect();
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+            }
+
+            PatKind::Struct(ref qpath, ref fields, _) => {
+                let def = self.tables.qpath_def(qpath, pat.hir_id);
+                let adt_def = match ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => {
+                        span_bug!(
+                            pat.span,
+                            "struct pattern not applied to an ADT");
+                    }
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                    fields.iter()
+                          .map(|field| {
+                              let index = variant_def.index_of_field_named(field.node.name);
+                              let index = index.unwrap_or_else(|| {
+                                  span_bug!(
+                                      pat.span,
+                                      "no field with name {:?}",
+                                      field.node.name);
+                              });
+                              FieldPattern {
+                                  field: Field::new(index),
+                                  pattern: self.lower_pattern(&field.node.pat),
+                              }
+                          })
+                          .collect();
+
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+            }
+        };
+
+        Pattern {
+            span: pat.span,
+            ty,
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
+        pats.iter().map(|p| self.lower_pattern(p)).collect()
+    }
+
+    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
+    {
+        pat.as_ref().map(|p| self.lower_pattern(p))
+    }
+
+    fn flatten_nested_slice_patterns(
+        &mut self,
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>)
+        -> (Vec<Pattern<'tcx>>, Option<Pattern<'tcx>>, Vec<Pattern<'tcx>>)
+    {
+        let orig_slice = match slice {
+            Some(orig_slice) => orig_slice,
+            None => return (prefix, slice, suffix)
+        };
+        let orig_prefix = prefix;
+        let orig_suffix = suffix;
+
+        // dance because of intentional borrow-checker stupidity.
+        let kind = *orig_slice.kind;
+        match kind {
+            PatternKind::Slice { prefix, slice, mut suffix } |
+            PatternKind::Array { prefix, slice, mut suffix } => {
+                let mut orig_prefix = orig_prefix;
+
+                orig_prefix.extend(prefix);
+                suffix.extend(orig_suffix);
+
+                (orig_prefix, slice, suffix)
+            }
+            _ => {
+                (orig_prefix, Some(Pattern {
+                    kind: box kind, ..orig_slice
+                }), orig_suffix)
+            }
+        }
+    }
+
+    fn slice_or_array_pattern(
+        &mut self,
+        span: Span,
+        ty: Ty<'tcx>,
+        prefix: &'tcx [P<hir::Pat>],
+        slice: &'tcx Option<P<hir::Pat>>,
+        suffix: &'tcx [P<hir::Pat>])
+        -> PatternKind<'tcx>
+    {
+        let prefix = self.lower_patterns(prefix);
+        let slice = self.lower_opt_pattern(slice);
+        let suffix = self.lower_patterns(suffix);
+        let (prefix, slice, suffix) =
+            self.flatten_nested_slice_patterns(prefix, slice, suffix);
+
+        match ty.sty {
+            ty::TySlice(..) => {
+                // matching a slice or fixed-length array
+                PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
+            }
+
+            ty::TyArray(_, len) => {
+                // fixed-length array
+                let len = len.val.unwrap_u64();
+                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
+                PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
+            }
+
+            _ => {
+                span_bug!(span, "bad slice pattern type {:?}", ty);
+            }
+        }
+    }
+
+    fn lower_variant_or_leaf(
+        &mut self,
+        def: Def,
+        span: Span,
+        ty: Ty<'tcx>,
+        subpatterns: Vec<FieldPattern<'tcx>>)
+        -> PatternKind<'tcx>
+    {
+        match def {
+            Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
+                let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
+                let adt_def = self.tcx.adt_def(enum_id);
+                if adt_def.is_enum() {
+                    let substs = match ty.sty {
+                        ty::TyAdt(_, substs) |
+                        ty::TyFnDef(_, substs) => substs,
+                        _ => bug!("inappropriate type for def: {:?}", ty.sty),
+                    };
+                    PatternKind::Variant {
+                        adt_def,
+                        substs,
+                        variant_index: adt_def.variant_index_with_id(variant_id),
+                        subpatterns,
+                    }
+                } else {
+                    PatternKind::Leaf { subpatterns: subpatterns }
+                }
+            }
+
+            Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
+                PatternKind::Leaf { subpatterns: subpatterns }
+            }
+
+            _ => {
+                self.errors.push(PatternError::NonConstPath(span));
+                PatternKind::Wild
+            }
+        }
+    }
+
+    fn lower_path(&mut self,
+                  qpath: &hir::QPath,
+                  id: hir::HirId,
+                  span: Span)
+                  -> Pattern<'tcx> {
+        let ty = self.tables.node_id_to_type(id);
+        let def = self.tables.qpath_def(qpath, id);
+        let kind = match def {
+            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                let substs = self.tables.node_substs(id);
+                match ty::Instance::resolve(
+                    self.tcx,
+                    self.param_env,
+                    def_id,
+                    substs,
+                ) {
+                    Some(instance) => {
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None,
+                        };
+                        match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
+                            Ok(value) => {
+                                return self.const_to_pat(instance, value, id, span)
+                            },
+                            Err(err) => {
+                                err.report(self.tcx, span, "pattern");
+                                PatternKind::Wild
+                            },
+                        }
+                    },
+                    None => {
+                        self.errors.push(PatternError::StaticInPattern(span));
+                        PatternKind::Wild
+                    },
+                }
+            }
+            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+        };
+
+        Pattern {
+            span,
+            ty,
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
+        match expr.node {
+            hir::ExprLit(ref lit) => {
+                let ty = self.tables.expr_ty(expr);
+                match lit_to_const(&lit.node, self.tcx, ty, false) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
+                }
+            },
+            hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
+            hir::ExprUnary(hir::UnNeg, ref expr) => {
+                let ty = self.tables.expr_ty(expr);
+                let lit = match expr.node {
+                    hir::ExprLit(ref lit) => lit,
+                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+                };
+                match lit_to_const(&lit.node, self.tcx, ty, true) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
+                }
+            }
+            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+        }
+    }
+
+    fn const_to_pat(
+        &self,
+        instance: ty::Instance<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+    ) -> Pattern<'tcx> {
+        debug!("const_to_pat: cv={:#?}", cv);
+        let kind = match cv.ty.sty {
+            ty::TyFloat(_) => {
+                let id = self.tcx.hir.hir_to_node_id(id);
+                self.tcx.lint_node(
+                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                    id,
+                    span,
+                    "floating-point types cannot be used in patterns",
+                );
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
+            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");
+                PatternKind::Wild
+            }
+            ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
+                let msg = 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));
+                self.tcx.sess.span_err(span, &msg);
+                PatternKind::Wild
+            },
+            ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
+                match cv.val {
+                    ConstVal::Value(val) => {
+                        let discr = const_discr(
+                            self.tcx, self.param_env, instance, val, cv.ty
+                        ).unwrap();
+                        let variant_index = adt_def
+                            .discriminants(self.tcx)
+                            .position(|var| var.val == discr)
+                            .unwrap();
+                        PatternKind::Variant {
+                            adt_def,
+                            substs,
+                            variant_index,
+                            subpatterns: adt_def
+                                .variants[variant_index]
+                                .fields
+                                .iter()
+                                .enumerate()
+                                .map(|(i, _)| {
+                                let field = Field::new(i);
+                                let val = match cv.val {
+                                    ConstVal::Value(miri) => const_val_field(
+                                        self.tcx, self.param_env, instance,
+                                        Some(variant_index), field, miri, cv.ty,
+                                    ).unwrap(),
+                                    _ => bug!("{:#?} is not a valid tuple", cv),
+                                };
+                                FieldPattern {
+                                    field,
+                                    pattern: self.const_to_pat(instance, val, id, span),
+                                }
+                            }).collect(),
+                        }
+                    },
+                    _ => return Pattern {
+                        span,
+                        ty: cv.ty,
+                        kind: Box::new(PatternKind::Constant {
+                            value: cv,
+                        }),
+                    }
+                }
+            },
+            ty::TyAdt(adt_def, _) => {
+                let struct_var = adt_def.non_enum_variant();
+                PatternKind::Leaf {
+                    subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| {
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        FieldPattern {
+                            field,
+                            pattern: self.const_to_pat(instance, val, id, span),
+                        }
+                    }).collect()
+                }
+            }
+            ty::TyTuple(fields, _) => {
+                PatternKind::Leaf {
+                    subpatterns: (0..fields.len()).map(|i| {
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        FieldPattern {
+                            field,
+                            pattern: self.const_to_pat(instance, val, id, span),
+                        }
+                    }).collect()
+                }
+            }
+            ty::TyArray(_, n) => {
+                PatternKind::Array {
+                    prefix: (0..n.val.unwrap_u64()).map(|i| {
+                        let i = i as usize;
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        self.const_to_pat(instance, val, id, span)
+                    }).collect(),
+                    slice: None,
+                    suffix: Vec::new(),
+                }
+            }
+            _ => {
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
+        };
+
+        Pattern {
+            span,
+            ty: cv.ty,
+            kind: Box::new(kind),
+        }
+    }
+}
+
+pub trait PatternFoldable<'tcx> : Sized {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.super_fold_with(folder)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
+}
+
+pub trait PatternFolder<'tcx> : Sized {
+    fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
+        pattern.super_fold_with(self)
+    }
+
+    fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
+        kind.super_fold_with(self)
+    }
+}
+
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let content: T = (**self).fold_with(folder);
+        box content
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
+        self.as_ref().map(|t| t.fold_with(folder))
+    }
+}
+
+macro_rules! CloneImpls {
+    (<$lt_tcx:tt> $($ty:ty),+) => {
+        $(
+            impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
+                fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
+                    Clone::clone(self)
+                }
+            }
+        )+
+    }
+}
+
+CloneImpls!{ <'tcx>
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
+    Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
+}
+
+impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        FieldPattern {
+            field: self.field.fold_with(folder),
+            pattern: self.pattern.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        Pattern {
+            ty: self.ty.fold_with(folder),
+            span: self.span.fold_with(folder),
+            kind: self.kind.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern_kind(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            PatternKind::Wild => PatternKind::Wild,
+            PatternKind::Binding {
+                mutability,
+                name,
+                mode,
+                var,
+                ty,
+                ref subpattern,
+            } => PatternKind::Binding {
+                mutability: mutability.fold_with(folder),
+                name: name.fold_with(folder),
+                mode: mode.fold_with(folder),
+                var: var.fold_with(folder),
+                ty: ty.fold_with(folder),
+                subpattern: subpattern.fold_with(folder),
+            },
+            PatternKind::Variant {
+                adt_def,
+                substs,
+                variant_index,
+                ref subpatterns,
+            } => PatternKind::Variant {
+                adt_def: adt_def.fold_with(folder),
+                substs: substs.fold_with(folder),
+                variant_index: variant_index.fold_with(folder),
+                subpatterns: subpatterns.fold_with(folder)
+            },
+            PatternKind::Leaf {
+                ref subpatterns,
+            } => PatternKind::Leaf {
+                subpatterns: subpatterns.fold_with(folder),
+            },
+            PatternKind::Deref {
+                ref subpattern,
+            } => PatternKind::Deref {
+                subpattern: subpattern.fold_with(folder),
+            },
+            PatternKind::Constant {
+                value
+            } => PatternKind::Constant {
+                value: value.fold_with(folder)
+            },
+            PatternKind::Range {
+                lo,
+                hi,
+                end,
+            } => PatternKind::Range {
+                lo: lo.fold_with(folder),
+                hi: hi.fold_with(folder),
+                end,
+            },
+            PatternKind::Slice {
+                ref prefix,
+                ref slice,
+                ref suffix,
+            } => PatternKind::Slice {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder)
+            },
+            PatternKind::Array {
+                ref prefix,
+                ref slice,
+                ref suffix
+            } => PatternKind::Array {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder)
+            },
+        }
+    }
+}
+
+pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
+    use rustc_const_math::ConstFloat;
+    trace!("compare_const_vals: {:?}, {:?}", a, b);
+    use rustc::mir::interpret::{Value, PrimVal};
+    match (a, b) {
+        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
+         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
+            match ty.sty {
+                ty::TyFloat(ty) => {
+                    let l = ConstFloat {
+                        bits: a,
+                        ty,
+                    };
+                    let r = ConstFloat {
+                        bits: b,
+                        ty,
+                    };
+                    // FIXME(oli-obk): report cmp errors?
+                    l.try_cmp(r).ok()
+                },
+                ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
+                _ => Some(a.cmp(&b)),
+            }
+        },
+        _ if a == b => Some(Ordering::Equal),
+        _ => None,
+    }
+}
+
+fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          ty: Ty<'tcx>,
+                          neg: bool)
+                          -> Result<ConstVal<'tcx>, ()> {
+    use syntax::ast::*;
+
+    use rustc::mir::interpret::*;
+    let lit = match *lit {
+        LitKind::Str(ref s, _) => {
+            let s = s.as_str();
+            let id = tcx.allocate_cached(s.as_bytes());
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByValPair(
+                PrimVal::Ptr(ptr),
+                PrimVal::from_u128(s.len() as u128),
+            )
+        },
+        LitKind::ByteStr(ref data) => {
+            let id = tcx.allocate_cached(data);
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByVal(PrimVal::Ptr(ptr))
+        },
+        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+        LitKind::Int(n, _) => {
+            enum Int {
+                Signed(IntTy),
+                Unsigned(UintTy),
+            }
+            let ty = match ty.sty {
+                ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
+                ty::TyInt(other) => Int::Signed(other),
+                ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
+                ty::TyUint(other) => Int::Unsigned(other),
+                _ => bug!(),
+            };
+            let n = match ty {
+                // FIXME(oli-obk): are these casts correct?
+                Int::Signed(IntTy::I8) if neg =>
+                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I16) if neg =>
+                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I32) if neg =>
+                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I64) if neg =>
+                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I128) if neg =>
+                    (n as i128).overflowing_neg().0 as u128,
+                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
+                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
+                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
+                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
+                Int::Signed(IntTy::I128) => n,
+                Int::Unsigned(UintTy::U8) => n as u8 as u128,
+                Int::Unsigned(UintTy::U16) => n as u16 as u128,
+                Int::Unsigned(UintTy::U32) => n as u32 as u128,
+                Int::Unsigned(UintTy::U64) => n as u64 as u128,
+                Int::Unsigned(UintTy::U128) => n,
+                _ => bug!(),
+            };
+            Value::ByVal(PrimVal::Bytes(n))
+        },
+        LitKind::Float(n, fty) => {
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::FloatUnsuffixed(n) => {
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
+            };
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
+        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+    };
+    Ok(ConstVal::Value(lit))
+}
+
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ()> {
+    ConstFloat::from_str(num, fty).map_err(|_| ())
+}
diff --git a/src/librustc_mir/hair/pattern/pattern.rs b/src/librustc_mir/hair/pattern/pattern.rs
new file mode 100644 (file)
index 0000000..2678984
--- /dev/null
@@ -0,0 +1,1187 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use interpret::{const_val_field, const_discr};
+
+use rustc::middle::const_val::ConstVal;
+use rustc::mir::{Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::subst::{Substs, Kind};
+use rustc::hir::{self, PatKind, RangeEnd};
+use rustc::hir::def::{Def, CtorKind};
+use rustc::hir::pat_util::EnumerateAndAdjustIterator;
+
+use rustc_data_structures::indexed_vec::Idx;
+use rustc_const_math::ConstFloat;
+
+use std::cmp::Ordering;
+use std::fmt;
+use syntax::ast;
+use syntax::ptr::P;
+use syntax_pos::Span;
+
+#[derive(Clone, Debug)]
+pub enum PatternError {
+    AssociatedConstInPattern(Span),
+    StaticInPattern(Span),
+    FloatBug,
+    NonConstPath(Span),
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum BindingMode<'tcx> {
+    ByValue,
+    ByRef(Region<'tcx>, BorrowKind),
+}
+
+#[derive(Clone, Debug)]
+pub struct FieldPattern<'tcx> {
+    pub field: Field,
+    pub pattern: Pattern<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Pattern<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub span: Span,
+    pub kind: Box<PatternKind<'tcx>>,
+}
+
+#[derive(Clone, Debug)]
+pub enum PatternKind<'tcx> {
+    Wild,
+
+    /// x, ref x, x @ P, etc
+    Binding {
+        mutability: Mutability,
+        name: ast::Name,
+        mode: BindingMode<'tcx>,
+        var: ast::NodeId,
+        ty: Ty<'tcx>,
+        subpattern: Option<Pattern<'tcx>>,
+    },
+
+    /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
+    Variant {
+        adt_def: &'tcx AdtDef,
+        substs: &'tcx Substs<'tcx>,
+        variant_index: usize,
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    },
+
+    /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
+    Leaf {
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    },
+
+    /// box P, &P, &mut P, etc
+    Deref {
+        subpattern: Pattern<'tcx>,
+    },
+
+    Constant {
+        value: &'tcx ty::Const<'tcx>,
+    },
+
+    Range {
+        lo: &'tcx ty::Const<'tcx>,
+        hi: &'tcx ty::Const<'tcx>,
+        end: RangeEnd,
+    },
+
+    /// matches against a slice, checking the length and extracting elements.
+    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+    /// e.g. `&[ref xs..]`.
+    Slice {
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>,
+    },
+
+    /// fixed match against an array, irrefutable
+    Array {
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>,
+    },
+}
+
+fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
+    match value.val {
+        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+        ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
+    }
+}
+
+fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
+    use rustc::ty::TypeVariants::*;
+    match (value, &ty.sty) {
+        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
+        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
+        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
+            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
+        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
+    }
+}
+
+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 ")?;
+                        match bk { BorrowKind::Mut { .. } => true, _ => false }
+                    }
+                };
+                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 {
+                        if !adt.is_enum() {
+                            Some(&adt.variants[0])
+                        } else {
+                            None
+                        }
+                    } 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::TyAdt(def, _) if def.is_box() => 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 { value } => {
+                print_const_val(value, f)
+            }
+            PatternKind::Range { lo, hi, end } => {
+                print_const_val(lo, f)?;
+                match end {
+                    RangeEnd::Included => write!(f, "...")?,
+                    RangeEnd::Excluded => 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, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
+    pub tables: &'a ty::TypeckTables<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
+    pub errors: Vec<PatternError>,
+}
+
+impl<'a, 'tcx> Pattern<'tcx> {
+    pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
+                    tables: &'a ty::TypeckTables<'tcx>,
+                    pat: &'tcx hir::Pat) -> Self {
+        let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
+        let result = pcx.lower_pattern(pat);
+        if !pcx.errors.is_empty() {
+            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
+            tcx.sess.delay_span_bug(pat.span, &msg);
+        }
+        debug!("Pattern::from_hir({:?}) = {:?}", pat, result);
+        result
+    }
+}
+
+impl<'a, 'tcx> PatternContext<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
+               tables: &'a ty::TypeckTables<'tcx>) -> Self {
+        PatternContext {
+            tcx,
+            param_env: param_env_and_substs.param_env,
+            tables,
+            substs: param_env_and_substs.value,
+            errors: vec![]
+        }
+    }
+
+    pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
+        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
+        // pattern has the type that results *after* dereferencing. For example, in this code:
+        //
+        // ```
+        // match &&Some(0i32) {
+        //     Some(n) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
+        // determined in rustc_typeck::check::match). The adjustments would be
+        //
+        // `vec![&&Option<i32>, &Option<i32>]`.
+        //
+        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
+        // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the
+        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
+        // gets the least-dereferenced type).
+        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
+        self.tables
+            .pat_adjustments()
+            .get(pat.hir_id)
+            .unwrap_or(&vec![])
+            .iter()
+            .rev()
+            .fold(unadjusted_pat, |pat, ref_ty| {
+                    debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
+                    Pattern {
+                        span: pat.span,
+                        ty: ref_ty,
+                        kind: Box::new(PatternKind::Deref { subpattern: pat }),
+                    }
+                },
+            )
+    }
+
+    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
+        let mut ty = self.tables.node_id_to_type(pat.hir_id);
+
+        let kind = match pat.node {
+            PatKind::Wild => PatternKind::Wild,
+
+            PatKind::Lit(ref value) => self.lower_lit(value),
+
+            PatKind::Range(ref lo_expr, ref hi_expr, end) => {
+                match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
+                    (PatternKind::Constant { value: lo },
+                     PatternKind::Constant { value: hi }) => {
+                        use std::cmp::Ordering;
+                        match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
+                            (RangeEnd::Excluded, Ordering::Less) => {},
+                            (RangeEnd::Excluded, _) => span_err!(
+                                self.tcx.sess,
+                                lo_expr.span,
+                                E0579,
+                                "lower range bound must be less than upper",
+                            ),
+                            (RangeEnd::Included, Ordering::Greater) => {
+                                struct_span_err!(self.tcx.sess, lo_expr.span, E0030,
+                                    "lower range bound must be less than or equal to upper")
+                                    .span_label(lo_expr.span, "lower bound larger than upper bound")
+                                    .emit();
+                            },
+                            (RangeEnd::Included, _) => {}
+                        }
+                        PatternKind::Range { lo, hi, end }
+                    }
+                    _ => PatternKind::Wild
+                }
+            }
+
+            PatKind::Path(ref qpath) => {
+                return self.lower_path(qpath, pat.hir_id, pat.span);
+            }
+
+            PatKind::Ref(ref subpattern, _) |
+            PatKind::Box(ref subpattern) => {
+                PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
+            }
+
+            PatKind::Slice(ref prefix, ref slice, ref suffix) => {
+                let ty = self.tables.node_id_to_type(pat.hir_id);
+                match ty.sty {
+                    ty::TyRef(_, mt) =>
+                        PatternKind::Deref {
+                            subpattern: Pattern {
+                                ty: mt.ty,
+                                span: pat.span,
+                                kind: Box::new(self.slice_or_array_pattern(
+                                    pat.span, mt.ty, prefix, slice, suffix))
+                            },
+                        },
+
+                    ty::TySlice(..) |
+                    ty::TyArray(..) =>
+                        self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
+
+                    ref sty =>
+                        span_bug!(
+                            pat.span,
+                            "unexpanded type for vector pattern: {:?}",
+                            sty),
+                }
+            }
+
+            PatKind::Tuple(ref subpatterns, ddpos) => {
+                let ty = self.tables.node_id_to_type(pat.hir_id);
+                match ty.sty {
+                    ty::TyTuple(ref tys, _) => {
+                        let subpatterns =
+                            subpatterns.iter()
+                                       .enumerate_and_adjust(tys.len(), ddpos)
+                                       .map(|(i, subpattern)| FieldPattern {
+                                            field: Field::new(i),
+                                            pattern: self.lower_pattern(subpattern)
+                                       })
+                                       .collect();
+
+                        PatternKind::Leaf { subpatterns: subpatterns }
+                    }
+
+                    ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
+                }
+            }
+
+            PatKind::Binding(_, id, ref ident, ref sub) => {
+                let var_ty = self.tables.node_id_to_type(pat.hir_id);
+                let region = match var_ty.sty {
+                    ty::TyRef(r, _) => Some(r),
+                    _ => None,
+                };
+                let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
+                                                         .expect("missing binding mode");
+                let (mutability, mode) = match bm {
+                    ty::BindByValue(hir::MutMutable) =>
+                        (Mutability::Mut, BindingMode::ByValue),
+                    ty::BindByValue(hir::MutImmutable) =>
+                        (Mutability::Not, BindingMode::ByValue),
+                    ty::BindByReference(hir::MutMutable) =>
+                        (Mutability::Not, BindingMode::ByRef(
+                            region.unwrap(), BorrowKind::Mut { allow_two_phase_borrow: false })),
+                    ty::BindByReference(hir::MutImmutable) =>
+                        (Mutability::Not, BindingMode::ByRef(
+                            region.unwrap(), BorrowKind::Shared)),
+                };
+
+                // A ref x pattern is the same node used for x, and as such it has
+                // x's type, which is &T, where we want T (the type being matched).
+                if let ty::BindByReference(_) = bm {
+                    if let ty::TyRef(_, mt) = ty.sty {
+                        ty = mt.ty;
+                    } else {
+                        bug!("`ref {}` has wrong type {}", ident.node, ty);
+                    }
+                }
+
+                PatternKind::Binding {
+                    mutability,
+                    mode,
+                    name: ident.node,
+                    var: id,
+                    ty: var_ty,
+                    subpattern: self.lower_opt_pattern(sub),
+                }
+            }
+
+            PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
+                let def = self.tables.qpath_def(qpath, pat.hir_id);
+                let adt_def = match ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                        subpatterns.iter()
+                                   .enumerate_and_adjust(variant_def.fields.len(), ddpos)
+                                   .map(|(i, field)| FieldPattern {
+                                       field: Field::new(i),
+                                       pattern: self.lower_pattern(field),
+                                   })
+                                   .collect();
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+            }
+
+            PatKind::Struct(ref qpath, ref fields, _) => {
+                let def = self.tables.qpath_def(qpath, pat.hir_id);
+                let adt_def = match ty.sty {
+                    ty::TyAdt(adt_def, _) => adt_def,
+                    _ => {
+                        span_bug!(
+                            pat.span,
+                            "struct pattern not applied to an ADT");
+                    }
+                };
+                let variant_def = adt_def.variant_of_def(def);
+
+                let subpatterns =
+                    fields.iter()
+                          .map(|field| {
+                              let index = variant_def.index_of_field_named(field.node.name);
+                              let index = index.unwrap_or_else(|| {
+                                  span_bug!(
+                                      pat.span,
+                                      "no field with name {:?}",
+                                      field.node.name);
+                              });
+                              FieldPattern {
+                                  field: Field::new(index),
+                                  pattern: self.lower_pattern(&field.node.pat),
+                              }
+                          })
+                          .collect();
+
+                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+            }
+        };
+
+        Pattern {
+            span: pat.span,
+            ty,
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
+        pats.iter().map(|p| self.lower_pattern(p)).collect()
+    }
+
+    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
+    {
+        pat.as_ref().map(|p| self.lower_pattern(p))
+    }
+
+    fn flatten_nested_slice_patterns(
+        &mut self,
+        prefix: Vec<Pattern<'tcx>>,
+        slice: Option<Pattern<'tcx>>,
+        suffix: Vec<Pattern<'tcx>>)
+        -> (Vec<Pattern<'tcx>>, Option<Pattern<'tcx>>, Vec<Pattern<'tcx>>)
+    {
+        let orig_slice = match slice {
+            Some(orig_slice) => orig_slice,
+            None => return (prefix, slice, suffix)
+        };
+        let orig_prefix = prefix;
+        let orig_suffix = suffix;
+
+        // dance because of intentional borrow-checker stupidity.
+        let kind = *orig_slice.kind;
+        match kind {
+            PatternKind::Slice { prefix, slice, mut suffix } |
+            PatternKind::Array { prefix, slice, mut suffix } => {
+                let mut orig_prefix = orig_prefix;
+
+                orig_prefix.extend(prefix);
+                suffix.extend(orig_suffix);
+
+                (orig_prefix, slice, suffix)
+            }
+            _ => {
+                (orig_prefix, Some(Pattern {
+                    kind: box kind, ..orig_slice
+                }), orig_suffix)
+            }
+        }
+    }
+
+    fn slice_or_array_pattern(
+        &mut self,
+        span: Span,
+        ty: Ty<'tcx>,
+        prefix: &'tcx [P<hir::Pat>],
+        slice: &'tcx Option<P<hir::Pat>>,
+        suffix: &'tcx [P<hir::Pat>])
+        -> PatternKind<'tcx>
+    {
+        let prefix = self.lower_patterns(prefix);
+        let slice = self.lower_opt_pattern(slice);
+        let suffix = self.lower_patterns(suffix);
+        let (prefix, slice, suffix) =
+            self.flatten_nested_slice_patterns(prefix, slice, suffix);
+
+        match ty.sty {
+            ty::TySlice(..) => {
+                // matching a slice or fixed-length array
+                PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
+            }
+
+            ty::TyArray(_, len) => {
+                // fixed-length array
+                let len = len.val.unwrap_u64();
+                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
+                PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
+            }
+
+            _ => {
+                span_bug!(span, "bad slice pattern type {:?}", ty);
+            }
+        }
+    }
+
+    fn lower_variant_or_leaf(
+        &mut self,
+        def: Def,
+        span: Span,
+        ty: Ty<'tcx>,
+        subpatterns: Vec<FieldPattern<'tcx>>)
+        -> PatternKind<'tcx>
+    {
+        match def {
+            Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
+                let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
+                let adt_def = self.tcx.adt_def(enum_id);
+                if adt_def.is_enum() {
+                    let substs = match ty.sty {
+                        ty::TyAdt(_, substs) |
+                        ty::TyFnDef(_, substs) => substs,
+                        _ => bug!("inappropriate type for def: {:?}", ty.sty),
+                    };
+                    PatternKind::Variant {
+                        adt_def,
+                        substs,
+                        variant_index: adt_def.variant_index_with_id(variant_id),
+                        subpatterns,
+                    }
+                } else {
+                    PatternKind::Leaf { subpatterns: subpatterns }
+                }
+            }
+
+            Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
+                PatternKind::Leaf { subpatterns: subpatterns }
+            }
+
+            _ => {
+                self.errors.push(PatternError::NonConstPath(span));
+                PatternKind::Wild
+            }
+        }
+    }
+
+    fn lower_path(&mut self,
+                  qpath: &hir::QPath,
+                  id: hir::HirId,
+                  span: Span)
+                  -> Pattern<'tcx> {
+        let ty = self.tables.node_id_to_type(id);
+        let def = self.tables.qpath_def(qpath, id);
+        let is_associated_const = match def {
+            Def::AssociatedConst(_) => true,
+            _ => false,
+        };
+        let kind = match def {
+            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+                let substs = self.tables.node_substs(id);
+                match ty::Instance::resolve(
+                    self.tcx,
+                    self.param_env,
+                    def_id,
+                    substs,
+                ) {
+                    Some(instance) => {
+                        let cid = GlobalId {
+                            instance,
+                            promoted: None,
+                        };
+                        match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
+                            Ok(value) => {
+                                return self.const_to_pat(instance, value, id, span)
+                            },
+                            Err(err) => {
+                                err.report(self.tcx, span, "pattern");
+                                PatternKind::Wild
+                            },
+                        }
+                    },
+                    None => {
+                        self.errors.push(if is_associated_const {
+                            PatternError::AssociatedConstInPattern(span)
+                        } else {
+                            PatternError::StaticInPattern(span)
+                        });
+                        PatternKind::Wild
+                    },
+                }
+            }
+            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+        };
+
+        Pattern {
+            span,
+            ty,
+            kind: Box::new(kind),
+        }
+    }
+
+    fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
+        match expr.node {
+            hir::ExprLit(ref lit) => {
+                let ty = self.tables.expr_ty(expr);
+                match lit_to_const(&lit.node, self.tcx, ty, false) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
+                }
+            },
+            hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
+            hir::ExprUnary(hir::UnNeg, ref expr) => {
+                let ty = self.tables.expr_ty(expr);
+                let lit = match expr.node {
+                    hir::ExprLit(ref lit) => lit,
+                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+                };
+                match lit_to_const(&lit.node, self.tcx, ty, true) {
+                    Ok(val) => {
+                        let instance = ty::Instance::new(
+                            self.tables.local_id_root.expect("literal outside any scope"),
+                            self.substs,
+                        );
+                        let cv = self.tcx.mk_const(ty::Const { val, ty });
+                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+                    },
+                    Err(()) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatternKind::Wild
+                    },
+                }
+            }
+            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+        }
+    }
+
+    fn const_to_pat(
+        &self,
+        instance: ty::Instance<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+    ) -> Pattern<'tcx> {
+        debug!("const_to_pat: cv={:#?}", cv);
+        let kind = match cv.ty.sty {
+            ty::TyFloat(_) => {
+                let id = self.tcx.hir.hir_to_node_id(id);
+                self.tcx.lint_node(
+                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                    id,
+                    span,
+                    "floating-point types cannot be used in patterns",
+                );
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
+            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");
+                PatternKind::Wild
+            }
+            ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
+                let msg = 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));
+                self.tcx.sess.span_err(span, &msg);
+                PatternKind::Wild
+            },
+            ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
+                match cv.val {
+                    ConstVal::Value(val) => {
+                        let discr = const_discr(
+                            self.tcx, self.param_env, instance, val, cv.ty
+                        ).unwrap();
+                        let variant_index = adt_def
+                            .discriminants(self.tcx)
+                            .position(|var| var.val == discr)
+                            .unwrap();
+                        PatternKind::Variant {
+                            adt_def,
+                            substs,
+                            variant_index,
+                            subpatterns: adt_def
+                                .variants[variant_index]
+                                .fields
+                                .iter()
+                                .enumerate()
+                                .map(|(i, _)| {
+                                let field = Field::new(i);
+                                let val = match cv.val {
+                                    ConstVal::Value(miri) => const_val_field(
+                                        self.tcx, self.param_env, instance,
+                                        Some(variant_index), field, miri, cv.ty,
+                                    ).unwrap(),
+                                    _ => bug!("{:#?} is not a valid tuple", cv),
+                                };
+                                FieldPattern {
+                                    field,
+                                    pattern: self.const_to_pat(instance, val, id, span),
+                                }
+                            }).collect(),
+                        }
+                    },
+                    _ => return Pattern {
+                        span,
+                        ty: cv.ty,
+                        kind: Box::new(PatternKind::Constant {
+                            value: cv,
+                        }),
+                    }
+                }
+            },
+            ty::TyAdt(adt_def, _) => {
+                let struct_var = adt_def.non_enum_variant();
+                PatternKind::Leaf {
+                    subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| {
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        FieldPattern {
+                            field,
+                            pattern: self.const_to_pat(instance, val, id, span),
+                        }
+                    }).collect()
+                }
+            }
+            ty::TyTuple(fields, _) => {
+                PatternKind::Leaf {
+                    subpatterns: (0..fields.len()).map(|i| {
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        FieldPattern {
+                            field,
+                            pattern: self.const_to_pat(instance, val, id, span),
+                        }
+                    }).collect()
+                }
+            }
+            ty::TyArray(_, n) => {
+                PatternKind::Array {
+                    prefix: (0..n.val.unwrap_u64()).map(|i| {
+                        let i = i as usize;
+                        let field = Field::new(i);
+                        let val = match cv.val {
+                            ConstVal::Value(miri) => const_val_field(
+                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
+                            ).unwrap(),
+                            _ => bug!("{:#?} is not a valid tuple", cv),
+                        };
+                        self.const_to_pat(instance, val, id, span)
+                    }).collect(),
+                    slice: None,
+                    suffix: Vec::new(),
+                }
+            }
+            _ => {
+                PatternKind::Constant {
+                    value: cv,
+                }
+            },
+        };
+
+        Pattern {
+            span,
+            ty: cv.ty,
+            kind: Box::new(kind),
+        }
+    }
+}
+
+pub trait PatternFoldable<'tcx> : Sized {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.super_fold_with(folder)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
+}
+
+pub trait PatternFolder<'tcx> : Sized {
+    fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
+        pattern.super_fold_with(self)
+    }
+
+    fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
+        kind.super_fold_with(self)
+    }
+}
+
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let content: T = (**self).fold_with(folder);
+        box content
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
+        self.as_ref().map(|t| t.fold_with(folder))
+    }
+}
+
+macro_rules! CloneImpls {
+    (<$lt_tcx:tt> $($ty:ty),+) => {
+        $(
+            impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
+                fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
+                    Clone::clone(self)
+                }
+            }
+        )+
+    }
+}
+
+CloneImpls!{ <'tcx>
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
+    Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
+}
+
+impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        FieldPattern {
+            field: self.field.fold_with(folder),
+            pattern: self.pattern.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        Pattern {
+            ty: self.ty.fold_with(folder),
+            span: self.span.fold_with(folder),
+            kind: self.kind.fold_with(folder)
+        }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern_kind(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            PatternKind::Wild => PatternKind::Wild,
+            PatternKind::Binding {
+                mutability,
+                name,
+                mode,
+                var,
+                ty,
+                ref subpattern,
+            } => PatternKind::Binding {
+                mutability: mutability.fold_with(folder),
+                name: name.fold_with(folder),
+                mode: mode.fold_with(folder),
+                var: var.fold_with(folder),
+                ty: ty.fold_with(folder),
+                subpattern: subpattern.fold_with(folder),
+            },
+            PatternKind::Variant {
+                adt_def,
+                substs,
+                variant_index,
+                ref subpatterns,
+            } => PatternKind::Variant {
+                adt_def: adt_def.fold_with(folder),
+                substs: substs.fold_with(folder),
+                variant_index: variant_index.fold_with(folder),
+                subpatterns: subpatterns.fold_with(folder)
+            },
+            PatternKind::Leaf {
+                ref subpatterns,
+            } => PatternKind::Leaf {
+                subpatterns: subpatterns.fold_with(folder),
+            },
+            PatternKind::Deref {
+                ref subpattern,
+            } => PatternKind::Deref {
+                subpattern: subpattern.fold_with(folder),
+            },
+            PatternKind::Constant {
+                value
+            } => PatternKind::Constant {
+                value: value.fold_with(folder)
+            },
+            PatternKind::Range {
+                lo,
+                hi,
+                end,
+            } => PatternKind::Range {
+                lo: lo.fold_with(folder),
+                hi: hi.fold_with(folder),
+                end,
+            },
+            PatternKind::Slice {
+                ref prefix,
+                ref slice,
+                ref suffix,
+            } => PatternKind::Slice {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder)
+            },
+            PatternKind::Array {
+                ref prefix,
+                ref slice,
+                ref suffix
+            } => PatternKind::Array {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder)
+            },
+        }
+    }
+}
+
+pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
+    use rustc_const_math::ConstFloat;
+    trace!("compare_const_vals: {:?}, {:?}", a, b);
+    use rustc::mir::interpret::{Value, PrimVal};
+    match (a, b) {
+        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
+         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
+            match ty.sty {
+                ty::TyFloat(ty) => {
+                    let l = ConstFloat {
+                        bits: a,
+                        ty,
+                    };
+                    let r = ConstFloat {
+                        bits: b,
+                        ty,
+                    };
+                    // FIXME(oli-obk): report cmp errors?
+                    l.try_cmp(r).ok()
+                },
+                ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
+                _ => Some(a.cmp(&b)),
+            }
+        },
+        _ if a == b => Some(Ordering::Equal),
+        _ => None,
+    }
+}
+
+fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          ty: Ty<'tcx>,
+                          neg: bool)
+                          -> Result<ConstVal<'tcx>, ()> {
+    use syntax::ast::*;
+
+    use rustc::mir::interpret::*;
+    let lit = match *lit {
+        LitKind::Str(ref s, _) => {
+            let s = s.as_str();
+            let id = tcx.allocate_cached(s.as_bytes());
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByValPair(
+                PrimVal::Ptr(ptr),
+                PrimVal::from_u128(s.len() as u128),
+            )
+        },
+        LitKind::ByteStr(ref data) => {
+            let id = tcx.allocate_cached(data);
+            let ptr = MemoryPointer::new(id, 0);
+            Value::ByVal(PrimVal::Ptr(ptr))
+        },
+        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+        LitKind::Int(n, _) => {
+            enum Int {
+                Signed(IntTy),
+                Unsigned(UintTy),
+            }
+            let ty = match ty.sty {
+                ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
+                ty::TyInt(other) => Int::Signed(other),
+                ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
+                ty::TyUint(other) => Int::Unsigned(other),
+                _ => bug!(),
+            };
+            let n = match ty {
+                // FIXME(oli-obk): are these casts correct?
+                Int::Signed(IntTy::I8) if neg =>
+                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I16) if neg =>
+                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I32) if neg =>
+                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I64) if neg =>
+                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+                Int::Signed(IntTy::I128) if neg =>
+                    (n as i128).overflowing_neg().0 as u128,
+                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
+                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
+                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
+                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
+                Int::Signed(IntTy::I128) => n,
+                Int::Unsigned(UintTy::U8) => n as u8 as u128,
+                Int::Unsigned(UintTy::U16) => n as u16 as u128,
+                Int::Unsigned(UintTy::U32) => n as u32 as u128,
+                Int::Unsigned(UintTy::U64) => n as u64 as u128,
+                Int::Unsigned(UintTy::U128) => n,
+                _ => bug!(),
+            };
+            Value::ByVal(PrimVal::Bytes(n))
+        },
+        LitKind::Float(n, fty) => {
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::FloatUnsuffixed(n) => {
+            let fty = match ty.sty {
+                ty::TyFloat(fty) => fty,
+                _ => bug!()
+            };
+            let n = n.as_str();
+            let mut f = parse_float(&n, fty)?;
+            if neg {
+                f = -f;
+            }
+            let bits = f.bits;
+            Value::ByVal(PrimVal::Bytes(bits))
+        }
+        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
+        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+    };
+    Ok(ConstVal::Value(lit))
+}
+
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+                     -> Result<ConstFloat, ()> {
+    ConstFloat::from_str(num, fty).map_err(|_| ())
+}
index f6ceaba29ac68cba6bbbf4744ccc2e1809ef7f0b..f6b38dcc00150c6467f9545cf5d45fbb737aa583 100644 (file)
@@ -71,9 +71,9 @@
 pub mod util;
 pub mod interpret;
 pub mod monomorphize;
-pub mod pattern;
 pub mod check_const_err;
 
+pub use hair::pattern::check_crate as matchck_crate;
 use rustc::ty::maps::Providers;
 
 pub fn provide(providers: &mut Providers) {
@@ -81,7 +81,7 @@ pub fn provide(providers: &mut Providers) {
     shim::provide(providers);
     transform::provide(providers);
     providers.const_eval = interpret::const_eval_provider;
-    providers.check_match = pattern::check_match;
+    providers.check_match = hair::pattern::check_match;
 }
 
 __build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
diff --git a/src/librustc_mir/pattern/_match.rs b/src/librustc_mir/pattern/_match.rs
deleted file mode 100644 (file)
index 3b31519..0000000
+++ /dev/null
@@ -1,1176 +0,0 @@
-// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use self::Constructor::*;
-use self::Usefulness::*;
-use self::WitnessPreference::*;
-
-use rustc::middle::const_val::ConstVal;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
-
-use super::pattern::{FieldPattern, Pattern, PatternKind};
-use super::pattern::{PatternFoldable, PatternFolder, compare_const_vals};
-
-use rustc::hir::def_id::DefId;
-use rustc::hir::RangeEnd;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-
-use rustc::mir::Field;
-use rustc::mir::interpret::{Value, PrimVal};
-use rustc::util::common::ErrorReported;
-
-use syntax_pos::{Span, DUMMY_SP};
-
-use arena::TypedArena;
-
-use std::cmp::{self, Ordering};
-use std::fmt;
-use std::iter::{FromIterator, IntoIterator, repeat};
-
-pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
-                                -> &'a Pattern<'tcx>
-{
-    cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
-}
-
-struct LiteralExpander;
-impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
-    fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> {
-        match (&pat.ty.sty, &*pat.kind) {
-            (&ty::TyRef(_, mt), &PatternKind::Constant { ref value }) => {
-                Pattern {
-                    ty: pat.ty,
-                    span: pat.span,
-                    kind: box PatternKind::Deref {
-                        subpattern: Pattern {
-                            ty: mt.ty,
-                            span: pat.span,
-                            kind: box PatternKind::Constant { value: value.clone() },
-                        }
-                    }
-                }
-            }
-            (_, &PatternKind::Binding { subpattern: Some(ref s), .. }) => {
-                s.fold_with(self)
-            }
-            _ => pat.super_fold_with(self)
-        }
-    }
-}
-
-impl<'tcx> Pattern<'tcx> {
-    fn is_wildcard(&self) -> bool {
-        match *self.kind {
-            PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild =>
-                true,
-            _ => false
-        }
-    }
-}
-
-pub struct Matrix<'a, 'tcx: 'a>(Vec<Vec<&'a Pattern<'tcx>>>);
-
-impl<'a, 'tcx> Matrix<'a, 'tcx> {
-    pub fn empty() -> Self {
-        Matrix(vec![])
-    }
-
-    pub fn push(&mut self, row: Vec<&'a Pattern<'tcx>>) {
-        self.0.push(row)
-    }
-}
-
-/// Pretty-printer for matrices of patterns, example:
-/// ++++++++++++++++++++++++++
-/// + _     + []             +
-/// ++++++++++++++++++++++++++
-/// + true  + [First]        +
-/// ++++++++++++++++++++++++++
-/// + true  + [Second(true)] +
-/// ++++++++++++++++++++++++++
-/// + false + [_]            +
-/// ++++++++++++++++++++++++++
-/// + _     + [_, _, ..tail] +
-/// ++++++++++++++++++++++++++
-impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "\n")?;
-
-        let &Matrix(ref m) = self;
-        let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
-            row.iter().map(|pat| format!("{:?}", pat)).collect()
-        }).collect();
-
-        let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
-        assert!(m.iter().all(|row| row.len() == column_count));
-        let column_widths: Vec<usize> = (0..column_count).map(|col| {
-            pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)
-        }).collect();
-
-        let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
-        let br = repeat('+').take(total_width).collect::<String>();
-        write!(f, "{}\n", br)?;
-        for row in pretty_printed_matrix {
-            write!(f, "+")?;
-            for (column, pat_str) in row.into_iter().enumerate() {
-                write!(f, " ")?;
-                write!(f, "{:1$}", pat_str, column_widths[column])?;
-                write!(f, " +")?;
-            }
-            write!(f, "\n")?;
-            write!(f, "{}\n", br)?;
-        }
-        Ok(())
-    }
-}
-
-impl<'a, 'tcx> FromIterator<Vec<&'a Pattern<'tcx>>> for Matrix<'a, 'tcx> {
-    fn from_iter<T: IntoIterator<Item=Vec<&'a Pattern<'tcx>>>>(iter: T) -> Self
-    {
-        Matrix(iter.into_iter().collect())
-    }
-}
-
-//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv
-pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    /// The module in which the match occurs. This is necessary for
-    /// checking inhabited-ness of types because whether a type is (visibly)
-    /// inhabited can depend on whether it was defined in the current module or
-    /// not. eg. `struct Foo { _private: ! }` cannot be seen to be empty
-    /// outside it's module and should not be matchable with an empty match
-    /// statement.
-    pub module: DefId,
-    pub pattern_arena: &'a TypedArena<Pattern<'tcx>>,
-    pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>,
-}
-
-impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
-    pub fn create_and_enter<F, R>(
-        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-        module: DefId,
-        f: F) -> R
-        where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R
-    {
-        let pattern_arena = TypedArena::new();
-
-        f(MatchCheckCtxt {
-            tcx,
-            module,
-            pattern_arena: &pattern_arena,
-            byte_array_map: FxHashMap(),
-        })
-    }
-
-    // convert a byte-string pattern to a list of u8 patterns.
-    fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Pattern<'tcx>>
-            where 'a: 'p
-    {
-        let pattern_arena = &*self.pattern_arena;
-        let tcx = self.tcx;
-        self.byte_array_map.entry(pat).or_insert_with(|| {
-            match pat.kind {
-                box PatternKind::Constant {
-                    value: &ty::Const { val: ConstVal::Value(b), ty }
-                } => {
-                    match b {
-                        Value::ByVal(PrimVal::Ptr(ptr)) => {
-                            let is_array_ptr = ty
-                                .builtin_deref(true, ty::NoPreference)
-                                .and_then(|t| t.ty.builtin_index())
-                                .map_or(false, |t| t == tcx.types.u8);
-                            assert!(is_array_ptr);
-                            let alloc = tcx
-                                .interpret_interner
-                                .get_alloc(ptr.alloc_id)
-                                .unwrap();
-                            assert_eq!(ptr.offset, 0);
-                            // FIXME: check length
-                            alloc.bytes.iter().map(|b| {
-                                &*pattern_arena.alloc(Pattern {
-                                    ty: tcx.types.u8,
-                                    span: pat.span,
-                                    kind: box PatternKind::Constant {
-                                        value: tcx.mk_const(ty::Const {
-                                            val: ConstVal::Value(Value::ByVal(
-                                                PrimVal::Bytes(*b as u128),
-                                            )),
-                                            ty: tcx.types.u8
-                                        })
-                                    }
-                                })
-                            }).collect()
-                        },
-                        _ => bug!("not a byte str: {:?}", b),
-                    }
-                }
-                _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
-            }
-        }).clone()
-    }
-
-    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
-        if self.tcx.features().never_type {
-            self.tcx.is_ty_uninhabited_from(self.module, ty)
-        } else {
-            false
-        }
-    }
-
-    fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
-        match ty.sty {
-            ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
-            _ => false,
-        }
-    }
-
-    fn is_local(&self, ty: Ty<'tcx>) -> bool {
-        match ty.sty {
-            ty::TyAdt(adt_def, ..) => adt_def.did.is_local(),
-            _ => false,
-        }
-    }
-
-    fn is_variant_uninhabited(&self,
-                              variant: &'tcx ty::VariantDef,
-                              substs: &'tcx ty::subst::Substs<'tcx>)
-                              -> bool
-    {
-        if self.tcx.features().never_type {
-            self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
-        } else {
-            false
-        }
-    }
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum Constructor<'tcx> {
-    /// The constructor of all patterns that don't vary by constructor,
-    /// e.g. struct patterns and fixed-length arrays.
-    Single,
-    /// Enum variants.
-    Variant(DefId),
-    /// Literal values.
-    ConstantValue(&'tcx ty::Const<'tcx>),
-    /// Ranges of literal values (`2...5` and `2..5`).
-    ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
-    /// Array patterns of length n.
-    Slice(u64),
-}
-
-impl<'tcx> Constructor<'tcx> {
-    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
-        match self {
-            &Variant(vid) => adt.variant_index_with_id(vid),
-            &Single => {
-                assert!(!adt.is_enum());
-                0
-            }
-            _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
-        }
-    }
-}
-
-#[derive(Clone)]
-pub enum Usefulness<'tcx> {
-    Useful,
-    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,
-    LeaveOutWitness
-}
-
-#[derive(Copy, Clone, Debug)]
-struct PatternContext<'tcx> {
-    ty: Ty<'tcx>,
-    max_slice_length: u64,
-}
-
-/// A stack of patterns in reverse order of construction
-#[derive(Clone)]
-pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);
-
-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>(
-        mut self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        ctor: &Constructor<'tcx>,
-        ty: Ty<'tcx>)
-        -> Self
-    {
-        let sub_pattern_tys = constructor_sub_pattern_tys(cx, ctor, ty);
-        self.0.extend(sub_pattern_tys.into_iter().map(|ty| {
-            Pattern {
-                ty,
-                span: DUMMY_SP,
-                kind: box PatternKind::Wild,
-            }
-        }));
-        self.apply_constructor(cx, ctor, ty)
-    }
-
-
-    /// Constructs a partial witness for a pattern given a list of
-    /// patterns expanded by the specialization step.
-    ///
-    /// When a pattern P is discovered to be useful, this function is used bottom-up
-    /// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
-    /// of values, V, where each value in that set is not covered by any previously
-    /// used patterns and is covered by the pattern P'. Examples:
-    ///
-    /// left_ty: tuple of 3 elements
-    /// pats: [10, 20, _]           => (10, 20, _)
-    ///
-    /// left_ty: struct X { a: (bool, &'static str), b: usize}
-    /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'a>(
-        mut self,
-        cx: &MatchCheckCtxt<'a,'tcx>,
-        ctor: &Constructor<'tcx>,
-        ty: Ty<'tcx>)
-        -> Self
-    {
-        let arity = constructor_arity(cx, ctor, ty);
-        let pat = {
-            let len = self.0.len() as u64;
-            let mut pats = self.0.drain((len-arity) as usize..).rev();
-
-            match ty.sty {
-                ty::TyAdt(..) |
-                ty::TyTuple(..) => {
-                    let pats = pats.enumerate().map(|(i, p)| {
-                        FieldPattern {
-                            field: Field::new(i),
-                            pattern: p
-                        }
-                    }).collect();
-
-                    if let ty::TyAdt(adt, substs) = ty.sty {
-                        if adt.is_enum() {
-                            PatternKind::Variant {
-                                adt_def: adt,
-                                substs,
-                                variant_index: ctor.variant_index_for_adt(adt),
-                                subpatterns: pats
-                            }
-                        } else {
-                            PatternKind::Leaf { subpatterns: pats }
-                        }
-                    } else {
-                        PatternKind::Leaf { subpatterns: pats }
-                    }
-                }
-
-                ty::TyRef(..) => {
-                    PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
-                }
-
-                ty::TySlice(_) | ty::TyArray(..) => {
-                    PatternKind::Slice {
-                        prefix: pats.collect(),
-                        slice: None,
-                        suffix: vec![]
-                    }
-                }
-
-                _ => {
-                    match *ctor {
-                        ConstantValue(value) => PatternKind::Constant { value },
-                        _ => PatternKind::Wild,
-                    }
-                }
-            }
-        };
-
-        self.0.push(Pattern {
-            ty,
-            span: DUMMY_SP,
-            kind: Box::new(pat),
-        });
-
-        self
-    }
-}
-
-/// This determines the set of all possible constructors of a pattern matching
-/// values of type `left_ty`. For vectors, this would normally be an infinite set
-/// but is instead bounded by the maximum fixed length of slice patterns in
-/// the column of patterns being analyzed.
-///
-/// This intentionally does not list ConstantValue specializations for
-/// non-booleans, because we currently assume that there is always a
-/// "non-standard constant" that matches. See issue #12483.
-///
-/// We make sure to omit constructors that are statically impossible. eg for
-/// Option<!> we do not include Some(_) in the returned list of constructors.
-fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                                  pcx: PatternContext<'tcx>)
-                                  -> Vec<Constructor<'tcx>>
-{
-    debug!("all_constructors({:?})", pcx.ty);
-    match pcx.ty.sty {
-        ty::TyBool => {
-            [true, false].iter().map(|&b| {
-                ConstantValue(cx.tcx.mk_const(ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
-                    ty: cx.tcx.types.bool
-                }))
-            }).collect()
-        }
-        ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
-            let len = len.val.unwrap_u64();
-            if len != 0 && cx.is_uninhabited(sub_ty) {
-                vec![]
-            } else {
-                vec![Slice(len)]
-            }
-        }
-        // Treat arrays of a constant but unknown length like slices.
-        ty::TyArray(ref sub_ty, _) |
-        ty::TySlice(ref sub_ty) => {
-            if cx.is_uninhabited(sub_ty) {
-                vec![Slice(0)]
-            } else {
-                (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
-            }
-        }
-        ty::TyAdt(def, substs) if def.is_enum() => {
-            def.variants.iter()
-                .filter(|v| !cx.is_variant_uninhabited(v, substs))
-                .map(|v| Variant(v.did))
-                .collect()
-        }
-        _ => {
-            if cx.is_uninhabited(pcx.ty) {
-                vec![]
-            } else {
-                vec![Single]
-            }
-        }
-    }
-}
-
-fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    patterns: I) -> u64
-    where I: Iterator<Item=&'p Pattern<'tcx>>
-{
-    // The exhaustiveness-checking paper does not include any details on
-    // checking variable-length slice patterns. However, they are matched
-    // by an infinite collection of fixed-length array patterns.
-    //
-    // Checking the infinite set directly would take an infinite amount
-    // of time. However, it turns out that for each finite set of
-    // patterns `P`, all sufficiently large array lengths are equivalent:
-    //
-    // Each slice `s` with a "sufficiently-large" length `l â‰¥ L` that applies
-    // to exactly the subset `Pâ‚œ` of `P` can be transformed to a slice
-    // `sₘ` for each sufficiently-large length `m` that applies to exactly
-    // the same subset of `P`.
-    //
-    // Because of that, each witness for reachability-checking from one
-    // of the sufficiently-large lengths can be transformed to an
-    // equally-valid witness from any other length, so we only have
-    // to check slice lengths from the "minimal sufficiently-large length"
-    // and below.
-    //
-    // Note that the fact that there is a *single* `sₘ` for each `m`
-    // not depending on the specific pattern in `P` is important: if
-    // you look at the pair of patterns
-    //     `[true, ..]`
-    //     `[.., false]`
-    // Then any slice of length â‰¥1 that matches one of these two
-    // patterns can be  be trivially turned to a slice of any
-    // other length â‰¥1 that matches them and vice-versa - for
-    // but the slice from length 2 `[false, true]` that matches neither
-    // of these patterns can't be turned to a slice from length 1 that
-    // matches neither of these patterns, so we have to consider
-    // slices from length 2 there.
-    //
-    // Now, to see that that length exists and find it, observe that slice
-    // patterns are either "fixed-length" patterns (`[_, _, _]`) or
-    // "variable-length" patterns (`[_, .., _]`).
-    //
-    // For fixed-length patterns, all slices with lengths *longer* than
-    // the pattern's length have the same outcome (of not matching), so
-    // as long as `L` is greater than the pattern's length we can pick
-    // any `sₘ` from that length and get the same result.
-    //
-    // For variable-length patterns, the situation is more complicated,
-    // because as seen above the precise value of `sₘ` matters.
-    //
-    // However, for each variable-length pattern `p` with a prefix of length
-    // `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
-    // `slâ‚š` elements are examined.
-    //
-    // Therefore, as long as `L` is positive (to avoid concerns about empty
-    // types), all elements after the maximum prefix length and before
-    // the maximum suffix length are not examined by any variable-length
-    // pattern, and therefore can be added/removed without affecting
-    // them - creating equivalent patterns from any sufficiently-large
-    // length.
-    //
-    // Of course, if fixed-length patterns exist, we must be sure
-    // that our length is large enough to miss them all, so
-    // we can pick `L = max(FIXED_LEN+1 âˆª {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
-    //
-    // for example, with the above pair of patterns, all elements
-    // but the first and last can be added/removed, so any
-    // witness of length â‰¥2 (say, `[false, false, true]`) can be
-    // turned to a witness from any other length â‰¥2.
-
-    let mut max_prefix_len = 0;
-    let mut max_suffix_len = 0;
-    let mut max_fixed_len = 0;
-
-    for row in patterns {
-        match *row.kind {
-            PatternKind::Constant {
-                value: &ty::Const {
-                    val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
-                    ty,
-                }
-            } => {
-                let is_array_ptr = ty
-                    .builtin_deref(true, ty::NoPreference)
-                    .and_then(|t| t.ty.builtin_index())
-                    .map_or(false, |t| t == cx.tcx.types.u8);
-                if is_array_ptr {
-                    let alloc = cx.tcx
-                        .interpret_interner
-                        .get_alloc(ptr.alloc_id)
-                        .unwrap();
-                    max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
-                }
-            }
-            PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
-                let fixed_len = prefix.len() as u64 + suffix.len() as u64;
-                max_fixed_len = cmp::max(max_fixed_len, fixed_len);
-            }
-            PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
-                max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
-                max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
-            }
-            _ => {}
-        }
-    }
-
-    cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
-}
-
-/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
-/// The algorithm from the paper has been modified to correctly handle empty
-/// types. The changes are:
-///   (0) We don't exit early if the pattern matrix has zero rows. We just
-///       continue to recurse over columns.
-///   (1) all_constructors will only return constructors that are statically
-///       possible. eg. it will only return Ok for Result<T, !>
-///
-/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
-/// to a set of such vectors `m` - this is defined as there being a set of
-/// inputs that will match `v` but not any of the sets in `m`.
-///
-/// All the patterns at each column of the `matrix ++ v` matrix must
-/// have the same type, except that wildcard (PatternKind::Wild) patterns
-/// with type TyErr are also allowed, even if the "type of the column"
-/// is not TyErr. That is used to represent private fields, as using their
-/// real type would assert that they are inhabited.
-///
-/// This is used both for reachability checking (if a pattern isn't useful in
-/// relation to preceding patterns, it is not reachable) and exhaustiveness
-/// checking (if a wildcard pattern is useful in relation to a matrix, the
-/// matrix isn't exhaustive).
-pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                                       matrix: &Matrix<'p, 'tcx>,
-                                       v: &[&'p Pattern<'tcx>],
-                                       witness: WitnessPreference)
-                                       -> Usefulness<'tcx> {
-    let &Matrix(ref rows) = matrix;
-    debug!("is_useful({:#?}, {:#?})", matrix, v);
-
-    // The base case. We are pattern-matching on () and the return value is
-    // based on whether our matrix has a row or not.
-    // NOTE: This could potentially be optimized by checking rows.is_empty()
-    // first and then, if v is non-empty, the return value is based on whether
-    // the type of the tuple we're checking is inhabited or not.
-    if v.is_empty() {
-        return if rows.is_empty() {
-            match witness {
-                ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
-                LeaveOutWitness => Useful,
-            }
-        } else {
-            NotUseful
-        }
-    };
-
-    assert!(rows.iter().all(|r| r.len() == v.len()));
-
-    let pcx = PatternContext {
-        // TyErr is used to represent the type of wildcard patterns matching
-        // against inaccessible (private) fields of structs, so that we won't
-        // be able to observe whether the types of the struct's fields are
-        // inhabited.
-        //
-        // If the field is truly inaccessible, then all the patterns
-        // matching against it must be wildcard patterns, so its type
-        // does not matter.
-        //
-        // However, if we are matching against non-wildcard patterns, we
-        // need to know the real type of the field so we can specialize
-        // against it. This primarily occurs through constants - they
-        // can include contents for fields that are inaccessible at the
-        // location of the match. In that case, the field's type is
-        // inhabited - by the constant - so we can just use it.
-        //
-        // FIXME: this might lead to "unstable" behavior with macro hygiene
-        // introducing uninhabited patterns for inaccessible fields. We
-        // need to figure out how to model that.
-        ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
-            .unwrap_or(v[0].ty),
-        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
-    };
-
-    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
-
-    if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
-        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.is_useful()).unwrap_or(NotUseful)
-    } else {
-        debug!("is_useful - expanding wildcard");
-
-        let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
-            pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
-        }).collect();
-        debug!("used_ctors = {:#?}", used_ctors);
-        let all_ctors = all_constructors(cx, pcx);
-        debug!("all_ctors = {:#?}", all_ctors);
-        let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
-            !used_ctors.contains(*c)
-        }).cloned().collect();
-
-        // `missing_ctors` is the set of constructors from the same type as the
-        // first column of `matrix` that are matched only by wildcard patterns
-        // from the first column.
-        //
-        // Therefore, if there is some pattern that is unmatched by `matrix`,
-        // it will still be unmatched if the first constructor is replaced by
-        // any of the constructors in `missing_ctors`
-        //
-        // However, if our scrutinee is *privately* an empty enum, we
-        // must treat it as though it had an "unknown" constructor (in
-        // that case, all other patterns obviously can't be variants)
-        // to avoid exposing its emptyness. See the `match_privately_empty`
-        // test for details.
-        //
-        // FIXME: currently the only way I know of something can
-        // be a privately-empty enum is when the never_type
-        // feature flag is not present, so this is only
-        // needed for that case.
-
-        let is_privately_empty =
-            all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
-        let is_declared_nonexhaustive =
-            cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
-        debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
-               missing_ctors, is_privately_empty, is_declared_nonexhaustive);
-
-        // For privately empty and non-exhaustive enums, we work as if there were an "extra"
-        // `_` constructor for the type, so we can never match over all constructors.
-        let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
-
-        if missing_ctors.is_empty() && !is_non_exhaustive {
-            all_ctors.into_iter().map(|c| {
-                is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
-            }).find(|result| result.is_useful()).unwrap_or(NotUseful)
-        } else {
-            let matrix = rows.iter().filter_map(|r| {
-                if r[0].is_wildcard() {
-                    Some(r[1..].to_vec())
-                } else {
-                    None
-                }
-            }).collect();
-            match is_useful(cx, &matrix, &v[1..], witness) {
-                UsefulWithWitness(pats) => {
-                    let cx = &*cx;
-                    // In this case, there's at least one "free"
-                    // constructor that is only matched against by
-                    // wildcard patterns.
-                    //
-                    // There are 2 ways we can report a witness here.
-                    // Commonly, we can report all the "free"
-                    // constructors as witnesses, e.g. if we have:
-                    //
-                    // ```
-                    //     enum Direction { N, S, E, W }
-                    //     let Direction::N = ...;
-                    // ```
-                    //
-                    // we can report 3 witnesses: `S`, `E`, and `W`.
-                    //
-                    // However, there are 2 cases where we don't want
-                    // to do this and instead report a single `_` witness:
-                    //
-                    // 1) If the user is matching against a non-exhaustive
-                    // enum, there is no point in enumerating all possible
-                    // variants, because the user can't actually match
-                    // against them himself, e.g. in an example like:
-                    // ```
-                    //     let err: io::ErrorKind = ...;
-                    //     match err {
-                    //         io::ErrorKind::NotFound => {},
-                    //     }
-                    // ```
-                    // we don't want to show every possible IO error,
-                    // but instead have `_` as the witness (this is
-                    // actually *required* if the user specified *all*
-                    // IO errors, but is probably what we want in every
-                    // case).
-                    //
-                    // 2) If the user didn't actually specify a constructor
-                    // in this arm, e.g. in
-                    // ```
-                    //     let x: (Direction, Direction, bool) = ...;
-                    //     let (_, _, false) = x;
-                    // ```
-                    // we don't want to show all 16 possible witnesses
-                    // `(<direction-1>, <direction-2>, true)` - we are
-                    // satisfied with `(_, _, true)`. In this case,
-                    // `used_ctors` is empty.
-                    let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
-                        // All constructors are unused. Add wild patterns
-                        // rather than each individual constructor
-                        pats.into_iter().map(|mut witness| {
-                            witness.0.push(Pattern {
-                                ty: pcx.ty,
-                                span: DUMMY_SP,
-                                kind: box PatternKind::Wild,
-                            });
-                            witness
-                        }).collect()
-                    } else {
-                        pats.into_iter().flat_map(|witness| {
-                            missing_ctors.iter().map(move |ctor| {
-                                witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
-                            })
-                        }).collect()
-                    };
-                    UsefulWithWitness(new_witnesses)
-                }
-                result => result
-            }
-        }
-    }
-}
-
-fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    &Matrix(ref m): &Matrix<'p, 'tcx>,
-    v: &[&'p Pattern<'tcx>],
-    ctor: Constructor<'tcx>,
-    lty: Ty<'tcx>,
-    witness: WitnessPreference) -> Usefulness<'tcx>
-{
-    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
-    let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
-    let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
-        Pattern {
-            ty,
-            span: DUMMY_SP,
-            kind: box PatternKind::Wild,
-        }
-    }).collect();
-    let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
-    let matrix = Matrix(m.iter().flat_map(|r| {
-        specialize(cx, &r, &ctor, &wild_patterns)
-    }).collect());
-    match specialize(cx, v, &ctor, &wild_patterns) {
-        Some(v) => match is_useful(cx, &matrix, &v, witness) {
-            UsefulWithWitness(witnesses) => UsefulWithWitness(
-                witnesses.into_iter()
-                    .map(|witness| witness.apply_constructor(cx, &ctor, lty))
-                    .collect()
-            ),
-            result => result
-        },
-        None => NotUseful
-    }
-}
-
-/// Determines the constructors that the given pattern can be specialized to.
-///
-/// In most cases, there's only one constructor that a specific pattern
-/// represents, such as a specific enum variant or a specific literal value.
-/// Slice patterns, however, can match slices of different lengths. For instance,
-/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
-///
-/// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
-                          pat: &Pattern<'tcx>,
-                          pcx: PatternContext)
-                          -> Option<Vec<Constructor<'tcx>>>
-{
-    match *pat.kind {
-        PatternKind::Binding { .. } | PatternKind::Wild =>
-            None,
-        PatternKind::Leaf { .. } | PatternKind::Deref { .. } =>
-            Some(vec![Single]),
-        PatternKind::Variant { adt_def, variant_index, .. } =>
-            Some(vec![Variant(adt_def.variants[variant_index].did)]),
-        PatternKind::Constant { value } =>
-            Some(vec![ConstantValue(value)]),
-        PatternKind::Range { lo, hi, end } =>
-            Some(vec![ConstantRange(lo, hi, end)]),
-        PatternKind::Array { .. } => match pcx.ty.sty {
-            ty::TyArray(_, length) => Some(vec![
-                Slice(length.val.unwrap_u64())
-            ]),
-            _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
-        },
-        PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-            let pat_len = prefix.len() as u64 + suffix.len() as u64;
-            if slice.is_some() {
-                Some((pat_len..pcx.max_slice_length+1).map(Slice).collect())
-            } else {
-                Some(vec![Slice(pat_len)])
-            }
-        }
-    }
-}
-
-/// This computes the arity of a constructor. The arity of a constructor
-/// is how many subpattern patterns of that constructor should be expanded to.
-///
-/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
-/// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
-    debug!("constructor_arity({:#?}, {:?})", ctor, ty);
-    match ty.sty {
-        ty::TyTuple(ref fs, _) => fs.len() as u64,
-        ty::TySlice(..) | ty::TyArray(..) => match *ctor {
-            Slice(length) => length,
-            ConstantValue(_) => 0,
-            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
-        },
-        ty::TyRef(..) => 1,
-        ty::TyAdt(adt, _) => {
-            adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
-        }
-        _ => 0
-    }
-}
-
-/// This computes the types of the sub patterns that a constructor should be
-/// expanded to.
-///
-/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
-fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
-                                             ctor: &Constructor,
-                                             ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
-{
-    debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
-    match ty.sty {
-        ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
-        ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
-            Slice(length) => (0..length).map(|_| ty).collect(),
-            ConstantValue(_) => vec![],
-            Single => vec![ty],
-            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
-        },
-        ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
-        ty::TyAdt(adt, substs) => {
-            if adt.is_box() {
-                // Use T as the sub pattern type of Box<T>.
-                vec![substs.type_at(0)]
-            } else {
-                if let ConstantValue(_) = *ctor {
-                    return vec![];
-                }
-                adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
-                    let is_visible = adt.is_enum()
-                        || field.vis.is_accessible_from(cx.module, cx.tcx);
-                    if is_visible {
-                        field.ty(cx.tcx, substs)
-                    } else {
-                        // Treat all non-visible fields as TyErr. They
-                        // can't appear in any other pattern from
-                        // this match (because they are private),
-                        // so their type does not matter - but
-                        // we don't want to know they are
-                        // uninhabited.
-                        cx.tcx.types.err
-                    }
-                }).collect()
-            }
-        }
-        _ => vec![],
-    }
-}
-
-fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
-                                    ctor: &Constructor,
-                                    prefix: &[Pattern],
-                                    slice: &Option<Pattern>,
-                                    suffix: &[Pattern])
-                                    -> Result<bool, ErrorReported> {
-    let data: &[u8] = match *ctor {
-        ConstantValue(&ty::Const { val: ConstVal::Value(
-            Value::ByVal(PrimVal::Ptr(ptr))
-        ), ty }) => {
-            let is_array_ptr = ty
-                .builtin_deref(true, ty::NoPreference)
-                .and_then(|t| t.ty.builtin_index())
-                .map_or(false, |t| t == tcx.types.u8);
-            assert!(is_array_ptr);
-            tcx
-                .interpret_interner
-                .get_alloc(ptr.alloc_id)
-                .unwrap()
-                .bytes
-                .as_ref()
-        }
-        _ => bug!()
-    };
-
-    let pat_len = prefix.len() + suffix.len();
-    if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
-        return Ok(false);
-    }
-
-    for (ch, pat) in
-        data[..prefix.len()].iter().zip(prefix).chain(
-            data[data.len()-suffix.len()..].iter().zip(suffix))
-    {
-        match pat.kind {
-            box PatternKind::Constant { value } => match value.val {
-                ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
-                    assert_eq!(b as u8 as u128, b);
-                    if b as u8 != *ch {
-                        return Ok(false);
-                    }
-                }
-                _ => span_bug!(pat.span, "bad const u8 {:?}", value)
-            },
-            _ => {}
-        }
-    }
-
-    Ok(true)
-}
-
-fn constructor_covered_by_range(ctor: &Constructor,
-                                from: &ConstVal, to: &ConstVal,
-                                end: RangeEnd,
-                                ty: Ty)
-                                -> Result<bool, ErrorReported> {
-    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
-    let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
-        .map(|res| res != Ordering::Less);
-    let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
-    macro_rules! some_or_ok {
-        ($e:expr) => {
-            match $e {
-                Some(to) => to,
-                None => return Ok(false), // not char or int
-            }
-        };
-    }
-    match *ctor {
-        ConstantValue(value) => {
-            let to = some_or_ok!(cmp_to(&value.val));
-            let end = (to == Ordering::Less) ||
-                      (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&value.val)) && end)
-        },
-        ConstantRange(from, to, RangeEnd::Included) => {
-            let to = some_or_ok!(cmp_to(&to.val));
-            let end = (to == Ordering::Less) ||
-                      (end == RangeEnd::Included && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
-        },
-        ConstantRange(from, to, RangeEnd::Excluded) => {
-            let to = some_or_ok!(cmp_to(&to.val));
-            let end = (to == Ordering::Less) ||
-                      (end == RangeEnd::Excluded && to == Ordering::Equal);
-            Ok(some_or_ok!(cmp_from(&from.val)) && end)
-        }
-        Variant(_) |
-        Single => Ok(true),
-        _ => bug!(),
-    }
-}
-
-fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>(
-    subpatterns: &'p [FieldPattern<'tcx>],
-    wild_patterns: &[&'p Pattern<'tcx>])
-    -> Vec<&'p Pattern<'tcx>>
-{
-    let mut result = wild_patterns.to_owned();
-
-    for subpat in subpatterns {
-        result[subpat.field.index()] = &subpat.pattern;
-    }
-
-    debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
-    result
-}
-
-/// This is the main specialization step. It expands the first pattern in the given row
-/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
-/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
-///
-/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple
-/// different patterns.
-/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
-/// fields filled with wild patterns.
-fn specialize<'p, 'a: 'p, 'tcx: 'a>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    r: &[&'p Pattern<'tcx>],
-    constructor: &Constructor<'tcx>,
-    wild_patterns: &[&'p Pattern<'tcx>])
-    -> Option<Vec<&'p Pattern<'tcx>>>
-{
-    let pat = &r[0];
-
-    let head: Option<Vec<&Pattern>> = match *pat.kind {
-        PatternKind::Binding { .. } | PatternKind::Wild => {
-            Some(wild_patterns.to_owned())
-        },
-
-        PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
-            let ref variant = adt_def.variants[variant_index];
-            if *constructor == Variant(variant.did) {
-                Some(patterns_for_variant(subpatterns, wild_patterns))
-            } else {
-                None
-            }
-        }
-
-        PatternKind::Leaf { ref subpatterns } => {
-            Some(patterns_for_variant(subpatterns, wild_patterns))
-        }
-        PatternKind::Deref { ref subpattern } => {
-            Some(vec![subpattern])
-        }
-
-        PatternKind::Constant { value } => {
-            match *constructor {
-                Slice(..) => match value.val {
-                    ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
-                        let is_array_ptr = value.ty
-                            .builtin_deref(true, ty::NoPreference)
-                            .and_then(|t| t.ty.builtin_index())
-                            .map_or(false, |t| t == cx.tcx.types.u8);
-                        assert!(is_array_ptr);
-                        let data_len = cx.tcx
-                            .interpret_interner
-                            .get_alloc(ptr.alloc_id)
-                            .unwrap()
-                            .bytes
-                            .len();
-                        if wild_patterns.len() == data_len {
-                            Some(cx.lower_byte_str_pattern(pat))
-                        } else {
-                            None
-                        }
-                    }
-                    _ => span_bug!(pat.span,
-                        "unexpected const-val {:?} with ctor {:?}", value, constructor)
-                },
-                _ => {
-                    match constructor_covered_by_range(
-                        constructor, &value.val, &value.val, RangeEnd::Included,
-                        value.ty,
-                            ) {
-                        Ok(true) => Some(vec![]),
-                        Ok(false) => None,
-                        Err(ErrorReported) => None,
-                    }
-                }
-            }
-        }
-
-        PatternKind::Range { lo, hi, ref end } => {
-            match constructor_covered_by_range(
-                constructor, &lo.val, &hi.val, end.clone(), lo.ty,
-            ) {
-                Ok(true) => Some(vec![]),
-                Ok(false) => None,
-                Err(ErrorReported) => None,
-            }
-        }
-
-        PatternKind::Array { ref prefix, ref slice, ref suffix } |
-        PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
-            match *constructor {
-                Slice(..) => {
-                    let pat_len = prefix.len() + suffix.len();
-                    if let Some(slice_count) = wild_patterns.len().checked_sub(pat_len) {
-                        if slice_count == 0 || slice.is_some() {
-                            Some(
-                                prefix.iter().chain(
-                                wild_patterns.iter().map(|p| *p)
-                                                    .skip(prefix.len())
-                                                    .take(slice_count)
-                                                    .chain(
-                                suffix.iter()
-                            )).collect())
-                        } else {
-                            None
-                        }
-                    } else {
-                        None
-                    }
-                }
-                ConstantValue(..) => {
-                    match slice_pat_covered_by_constructor(
-                        cx.tcx, pat.span, constructor, prefix, slice, suffix
-                            ) {
-                        Ok(true) => Some(vec![]),
-                        Ok(false) => None,
-                        Err(ErrorReported) => None
-                    }
-                }
-                _ => span_bug!(pat.span,
-                    "unexpected ctor {:?} for slice pat", constructor)
-            }
-        }
-    };
-    debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head);
-
-    head.map(|mut head| {
-        head.extend_from_slice(&r[1 ..]);
-        head
-    })
-}
diff --git a/src/librustc_mir/pattern/check_match.rs b/src/librustc_mir/pattern/check_match.rs
deleted file mode 100644 (file)
index 05f17c1..0000000
+++ /dev/null
@@ -1,646 +0,0 @@
-// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
-use super::_match::Usefulness::*;
-use super::_match::WitnessPreference::*;
-
-use super::pattern::{Pattern, PatternContext, PatternError, PatternKind};
-
-use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
-use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization::{cmt};
-use rustc::middle::region;
-use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::subst::Substs;
-use rustc::lint;
-use rustc_errors::DiagnosticBuilder;
-use rustc::util::common::ErrorReported;
-
-use rustc::hir::def::*;
-use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, Pat, PatKind};
-
-use std::slice;
-
-use syntax::ast;
-use syntax::ptr::P;
-use syntax_pos::{Span, DUMMY_SP};
-
-struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
-
-impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-    }
-
-    fn visit_body(&mut self, body: &'tcx hir::Body) {
-        intravisit::walk_body(self, body);
-        let def_id = self.tcx.hir.body_owner_def_id(body.id());
-        let _ = self.tcx.check_match(def_id);
-    }
-}
-
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.hir.krate().visit_all_item_likes(&mut OuterVisitor { tcx: tcx }.as_deep_visitor());
-    tcx.sess.abort_if_errors();
-}
-
-pub(crate) fn check_match<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_id: DefId,
-) -> Result<(), ErrorReported> {
-    let body_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
-        tcx.hir.body_owned_by(id)
-    } else {
-        return Ok(());
-    };
-
-    tcx.sess.track_errors(|| {
-        MatchVisitor {
-            tcx,
-            tables: tcx.body_tables(body_id),
-            region_scope_tree: &tcx.region_scope_tree(def_id),
-            param_env: tcx.param_env(def_id),
-            identity_substs: Substs::identity_for_item(tcx, def_id),
-        }.visit_body(tcx.hir.body(body_id));
-    })
-}
-
-fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
-    struct_span_err!(sess, sp, E0004, "{}", &error_message)
-}
-
-struct MatchVisitor<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    identity_substs: &'tcx Substs<'tcx>,
-    region_scope_tree: &'a region::ScopeTree,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
-        intravisit::walk_expr(self, ex);
-
-        match ex.node {
-            hir::ExprMatch(ref scrut, ref arms, source) => {
-                self.check_match(scrut, arms, source);
-            }
-            _ => {}
-        }
-    }
-
-    fn visit_local(&mut self, loc: &'tcx hir::Local) {
-        intravisit::walk_local(self, loc);
-
-        self.check_irrefutable(&loc.pat, match loc.source {
-            hir::LocalSource::Normal => "local binding",
-            hir::LocalSource::ForLoopDesugar => "`for` loop binding",
-        });
-
-        // Check legality of move bindings and `@` patterns.
-        self.check_patterns(false, slice::from_ref(&loc.pat));
-    }
-
-    fn visit_body(&mut self, body: &'tcx hir::Body) {
-        intravisit::walk_body(self, body);
-
-        for arg in &body.arguments {
-            self.check_irrefutable(&arg.pat, "function argument");
-            self.check_patterns(false, slice::from_ref(&arg.pat));
-        }
-    }
-}
-
-
-impl<'a, 'tcx> PatternContext<'a, 'tcx> {
-    fn report_inlining_errors(&self, pat_span: Span) {
-        for error in &self.errors {
-            match *error {
-                PatternError::StaticInPattern(span) => {
-                    self.span_e0158(span, "statics cannot be referenced in patterns")
-                }
-                PatternError::AssociatedConstInPattern(span) => {
-                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
-                }
-                PatternError::FloatBug => {
-                    // FIXME(#31407) this is only necessary because float parsing is buggy
-                    ::rustc::middle::const_val::struct_error(
-                        self.tcx, pat_span,
-                        "could not evaluate float literal (see issue #31407)",
-                    ).emit();
-                }
-                PatternError::NonConstPath(span) => {
-                    ::rustc::middle::const_val::struct_error(
-                        self.tcx, span,
-                        "runtime values cannot be referenced in patterns",
-                    ).emit();
-                }
-            }
-        }
-    }
-
-    fn span_e0158(&self, span: Span, text: &str) {
-        span_err!(self.tcx.sess, span, E0158, "{}", text)
-    }
-}
-
-impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
-    fn check_patterns(&self, has_guard: bool, pats: &[P<Pat>]) {
-        check_legality_of_move_bindings(self, has_guard, pats);
-        for pat in pats {
-            check_legality_of_bindings_in_at_patterns(self, pat);
-        }
-    }
-
-    fn check_match(
-        &self,
-        scrut: &hir::Expr,
-        arms: &'tcx [hir::Arm],
-        source: hir::MatchSource)
-    {
-        for arm in arms {
-            // First, check legality of move bindings.
-            self.check_patterns(arm.guard.is_some(), &arm.pats);
-
-            // Second, if there is a guard on each arm, make sure it isn't
-            // assigning or borrowing anything mutably.
-            if let Some(ref guard) = arm.guard {
-                check_for_mutation_in_guard(self, &guard);
-            }
-
-            // Third, perform some lints.
-            for pat in &arm.pats {
-                check_for_bindings_named_the_same_as_variants(self, pat);
-            }
-        }
-
-        let module = self.tcx.hir.get_module_parent(scrut.id);
-        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
-            let mut have_errors = false;
-
-            let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
-                arm.pats.iter().map(|pat| {
-                    let mut patcx = PatternContext::new(self.tcx,
-                                                        self.param_env.and(self.identity_substs),
-                                                        self.tables);
-                    let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
-                    if !patcx.errors.is_empty() {
-                        patcx.report_inlining_errors(pat.span);
-                        have_errors = true;
-                    }
-                    (pattern, &**pat)
-                }).collect(),
-                arm.guard.as_ref().map(|e| &**e)
-            )).collect();
-
-            // Bail out early if inlining failed.
-            if have_errors {
-                return;
-            }
-
-            // Fourth, check for unreachable arms.
-            check_arms(cx, &inlined_arms, source);
-
-            // Then, if the match has no arms, check whether the scrutinee
-            // is uninhabited.
-            let pat_ty = self.tables.node_id_to_type(scrut.hir_id);
-            let module = self.tcx.hir.get_module_parent(scrut.id);
-            if inlined_arms.is_empty() {
-                let scrutinee_is_uninhabited = if self.tcx.features().never_type {
-                    self.tcx.is_ty_uninhabited_from(module, pat_ty)
-                } else {
-                    self.conservative_is_uninhabited(pat_ty)
-                };
-                if !scrutinee_is_uninhabited {
-                    // We know the type is inhabited, so this must be wrong
-                    let mut err = create_e0004(self.tcx.sess, scrut.span,
-                                               format!("non-exhaustive patterns: type {} \
-                                                        is non-empty",
-                                                       pat_ty));
-                    span_help!(&mut err, scrut.span,
-                               "Please ensure that all possible cases are being handled; \
-                                possibly adding wildcards or more match arms.");
-                    err.emit();
-                }
-                // If the type *is* uninhabited, it's vacuously exhaustive
-                return;
-            }
-
-            let matrix: Matrix = inlined_arms
-                .iter()
-                .filter(|&&(_, guard)| guard.is_none())
-                .flat_map(|arm| &arm.0)
-                .map(|pat| vec![pat.0])
-                .collect();
-            let scrut_ty = self.tables.node_id_to_type(scrut.hir_id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
-        })
-    }
-
-    fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
-        // "rustc-1.0-style" uncontentious uninhabitableness check
-        match scrutinee_ty.sty {
-            ty::TyNever => true,
-            ty::TyAdt(def, _) => def.variants.is_empty(),
-            _ => false
-        }
-    }
-
-    fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
-        let module = self.tcx.hir.get_module_parent(pat.id);
-        MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
-            let mut patcx = PatternContext::new(self.tcx,
-                                                self.param_env.and(self.identity_substs),
-                                                self.tables);
-            let pattern = patcx.lower_pattern(pat);
-            let pattern_ty = pattern.ty;
-            let pats : Matrix = vec![vec![
-                expand_pattern(cx, pattern)
-            ]].into_iter().collect();
-
-            let wild_pattern = Pattern {
-                ty: pattern_ty,
-                span: DUMMY_SP,
-                kind: box PatternKind::Wild,
-            };
-            let witness = match is_useful(cx, &pats, &[&wild_pattern], ConstructWitness) {
-                UsefulWithWitness(witness) => witness,
-                NotUseful => return,
-                Useful => bug!()
-            };
-
-            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",
-                origin, pattern_string
-            );
-            let label_msg = match pat.node {
-                PatKind::Path(hir::QPath::Resolved(None, ref path))
-                        if path.segments.len() == 1 && path.segments[0].parameters.is_none() => {
-                    format!("interpreted as a {} pattern, not new variable", path.def.kind_name())
-                }
-                _ => format!("pattern `{}` not covered", pattern_string),
-            };
-            diag.span_label(pat.span, label_msg);
-            diag.emit();
-        });
-    }
-}
-
-fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
-    pat.walk(|p| {
-        if let PatKind::Binding(_, _, name, None) = p.node {
-            let bm = *cx.tables
-                        .pat_binding_modes()
-                        .get(p.hir_id)
-                        .expect("missing binding mode");
-
-            if bm != ty::BindByValue(hir::MutImmutable) {
-                // Nothing to check.
-                return true;
-            }
-            let pat_ty = cx.tables.pat_ty(p);
-            if let ty::TyAdt(edef, _) = pat_ty.sty {
-                if edef.is_enum() && edef.variants.iter().any(|variant| {
-                    variant.name == name.node && variant.ctor_kind == CtorKind::Const
-                }) {
-                    let ty_path = cx.tcx.item_path_str(edef.did);
-                    let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
-                        "pattern binding `{}` is named the same as one \
-                         of the variants of the type `{}`",
-                        name.node, ty_path);
-                    help!(err,
-                        "if you meant to match on a variant, \
-                        consider making the path in the pattern qualified: `{}::{}`",
-                        ty_path, name.node);
-                    err.emit();
-                }
-            }
-        }
-        true
-    });
-}
-
-/// Checks for common cases of "catchall" patterns that may not be intended as such.
-fn pat_is_catchall(pat: &Pat) -> bool {
-    match pat.node {
-        PatKind::Binding(.., None) => true,
-        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
-        PatKind::Ref(ref s, _) => pat_is_catchall(s),
-        PatKind::Tuple(ref v, _) => v.iter().all(|p| {
-            pat_is_catchall(&p)
-        }),
-        _ => false
-    }
-}
-
-// Check for unreachable patterns
-fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                        arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)],
-                        source: hir::MatchSource)
-{
-    let mut seen = Matrix::empty();
-    let mut catchall = None;
-    let mut printed_if_let_err = false;
-    for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
-        for &(pat, hir_pat) in pats {
-            let v = vec![pat];
-
-            match is_useful(cx, &seen, &v, LeaveOutWitness) {
-                NotUseful => {
-                    match source {
-                        hir::MatchSource::IfLetDesugar { .. } => {
-                            if printed_if_let_err {
-                                // we already printed an irrefutable if-let pattern error.
-                                // We don't want two, that's just confusing.
-                            } else {
-                                // find the first arm pattern so we can use its span
-                                let &(ref first_arm_pats, _) = &arms[0];
-                                let first_pat = &first_arm_pats[0];
-                                let span = first_pat.0.span;
-                                struct_span_err!(cx.tcx.sess, span, E0162,
-                                                "irrefutable if-let pattern")
-                                    .span_label(span, "irrefutable pattern")
-                                    .emit();
-                                printed_if_let_err = true;
-                            }
-                        },
-
-                        hir::MatchSource::WhileLetDesugar => {
-                            // find the first arm pattern so we can use its span
-                            let &(ref first_arm_pats, _) = &arms[0];
-                            let first_pat = &first_arm_pats[0];
-                            let span = first_pat.0.span;
-
-                            // check which arm we're on.
-                            match arm_index {
-                                // The arm with the user-specified pattern.
-                                0 => {
-                                    cx.tcx.lint_node(
-                                            lint::builtin::UNREACHABLE_PATTERNS,
-                                        hir_pat.id, pat.span,
-                                        "unreachable pattern");
-                                },
-                                // The arm with the wildcard pattern.
-                                1 => {
-                                    struct_span_err!(cx.tcx.sess, span, E0165,
-                                                     "irrefutable while-let pattern")
-                                        .span_label(span, "irrefutable pattern")
-                                        .emit();
-                                },
-                                _ => bug!(),
-                            }
-                        },
-
-                        hir::MatchSource::ForLoopDesugar |
-                        hir::MatchSource::Normal => {
-                            let mut err = cx.tcx.struct_span_lint_node(
-                                lint::builtin::UNREACHABLE_PATTERNS,
-                                hir_pat.id,
-                                pat.span,
-                                "unreachable pattern",
-                            );
-                            // if we had a catchall pattern, hint at that
-                            if let Some(catchall) = catchall {
-                                err.span_label(pat.span, "unreachable pattern");
-                                err.span_label(catchall, "matches any value");
-                            }
-                            err.emit();
-                        },
-
-                        // Unreachable patterns in try expressions occur when one of the arms
-                        // are an uninhabited type. Which is OK.
-                        hir::MatchSource::TryDesugar => {}
-                    }
-                }
-                Useful => (),
-                UsefulWithWitness(_) => bug!()
-            }
-            if guard.is_none() {
-                seen.push(v);
-                if catchall.is_none() && pat_is_catchall(hir_pat) {
-                    catchall = Some(pat.span);
-                }
-            }
-        }
-    }
-}
-
-fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
-                              scrut_ty: Ty<'tcx>,
-                              sp: Span,
-                              matrix: &Matrix<'a, 'tcx>) {
-    let wild_pattern = Pattern {
-        ty: scrut_ty,
-        span: DUMMY_SP,
-        kind: box PatternKind::Wild,
-    };
-    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
-        UsefulWithWitness(pats) => {
-            let witnesses = if pats.is_empty() {
-                vec![&wild_pattern]
-            } else {
-                pats.iter().map(|w| w.single_pattern()).collect()
-            };
-
-            const LIMIT: usize = 3;
-            let joined_patterns = match witnesses.len() {
-                0 => bug!(),
-                1 => format!("`{}`", witnesses[0]),
-                2...LIMIT => {
-                    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) = 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 witnesses.len() {
-                1 => format!("pattern {} not covered", joined_patterns),
-                _ => format!("patterns {} not covered", joined_patterns)
-            };
-            create_e0004(cx.tcx.sess, sp,
-                            format!("non-exhaustive patterns: {} not covered",
-                                    joined_patterns))
-                .span_label(sp, label_text)
-                .emit();
-        }
-        NotUseful => {
-            // This is good, wildcard pattern isn't reachable
-        },
-        _ => bug!()
-    }
-}
-
-// Legality of move bindings checking
-fn check_legality_of_move_bindings(cx: &MatchVisitor,
-                                   has_guard: bool,
-                                   pats: &[P<Pat>]) {
-    let mut by_ref_span = None;
-    for pat in pats {
-        pat.each_binding(|_, id, span, _path| {
-            let hir_id = cx.tcx.hir.node_to_hir_id(id);
-            let bm = *cx.tables
-                        .pat_binding_modes()
-                        .get(hir_id)
-                        .expect("missing binding mode");
-            if let ty::BindByReference(..) = bm {
-                by_ref_span = Some(span);
-            }
-        })
-    }
-
-    let check_move = |p: &Pat, sub: Option<&Pat>| {
-        // check legality of moving out of the enum
-
-        // x @ Foo(..) is legal, but x @ Foo(y) isn't.
-        if sub.map_or(false, |p| p.contains_bindings()) {
-            struct_span_err!(cx.tcx.sess, p.span, E0007,
-                             "cannot bind by-move with sub-bindings")
-                .span_label(p.span, "binds an already bound by-move value by moving it")
-                .emit();
-        } else if has_guard {
-            struct_span_err!(cx.tcx.sess, p.span, E0008,
-                      "cannot bind by-move into a pattern guard")
-                .span_label(p.span, "moves value into pattern guard")
-                .emit();
-        } else if by_ref_span.is_some() {
-            struct_span_err!(cx.tcx.sess, p.span, E0009,
-                            "cannot bind by-move and by-ref in the same pattern")
-                    .span_label(p.span, "by-move pattern here")
-                    .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
-                    .emit();
-        }
-    };
-
-    for pat in pats {
-        pat.walk(|p| {
-            if let PatKind::Binding(_, _, _, ref sub) = p.node {
-                let bm = *cx.tables
-                            .pat_binding_modes()
-                            .get(p.hir_id)
-                            .expect("missing binding mode");
-                match bm {
-                    ty::BindByValue(..) => {
-                        let pat_ty = cx.tables.node_id_to_type(p.hir_id);
-                        if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
-                            check_move(p, sub.as_ref().map(|p| &**p));
-                        }
-                    }
-                    _ => {}
-                }
-            }
-            true
-        });
-    }
-}
-
-/// Ensures that a pattern guard doesn't borrow by mutable reference or
-/// assign.
-///
-/// FIXME: this should be done by borrowck.
-fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    let mut checker = MutationChecker {
-        cx,
-    };
-    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
-        .walk_expr(guard);
-}
-
-struct MutationChecker<'a, 'tcx: 'a> {
-    cx: &'a MatchVisitor<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
-    fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
-    fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {}
-    fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
-    fn borrow(&mut self,
-              _: ast::NodeId,
-              span: Span,
-              _: cmt,
-              _: ty::Region<'tcx>,
-              kind:ty:: BorrowKind,
-              _: LoanCause) {
-        match kind {
-            ty::MutBorrow => {
-                struct_span_err!(self.cx.tcx.sess, span, E0301,
-                          "cannot mutably borrow in a pattern guard")
-                    .span_label(span, "borrowed mutably in pattern guard")
-                    .emit();
-            }
-            ty::ImmBorrow | ty::UniqueImmBorrow => {}
-        }
-    }
-    fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {}
-    fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) {
-        match mode {
-            MutateMode::JustWrite | MutateMode::WriteAndRead => {
-                struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
-                    .span_label(span, "assignment in pattern guard")
-                    .emit();
-            }
-            MutateMode::Init => {}
-        }
-    }
-}
-
-/// Forbids bindings in `@` patterns. This is necessary for memory safety,
-/// because of the way rvalues are handled in the borrow check. (See issue
-/// #14587.)
-fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor, pat: &Pat) {
-    AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
-}
-
-struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
-    cx: &'a MatchVisitor<'b, 'tcx>,
-    bindings_allowed: bool
-}
-
-impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_pat(&mut self, pat: &Pat) {
-        match pat.node {
-            PatKind::Binding(.., ref subpat) => {
-                if !self.bindings_allowed {
-                    struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
-                                     "pattern bindings are not allowed after an `@`")
-                        .span_label(pat.span,  "not allowed after `@`")
-                        .emit();
-                }
-
-                if subpat.is_some() {
-                    let bindings_were_allowed = self.bindings_allowed;
-                    self.bindings_allowed = false;
-                    intravisit::walk_pat(self, pat);
-                    self.bindings_allowed = bindings_were_allowed;
-                }
-            }
-            _ => intravisit::walk_pat(self, pat),
-        }
-    }
-}
diff --git a/src/librustc_mir/pattern/mod.rs b/src/librustc_mir/pattern/mod.rs
deleted file mode 100644 (file)
index c99dc4a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! constant evaluation on the HIR and code to validate patterns/matches
-
-mod _match;
-mod check_match;
-pub(crate) mod pattern;
-
-pub use self::check_match::check_crate;
-pub(crate) use self::check_match::check_match;
diff --git a/src/librustc_mir/pattern/pattern.rs b/src/librustc_mir/pattern/pattern.rs
deleted file mode 100644 (file)
index 2678984..0000000
+++ /dev/null
@@ -1,1187 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use interpret::{const_val_field, const_discr};
-
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
-use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
-use rustc::ty::subst::{Substs, Kind};
-use rustc::hir::{self, PatKind, RangeEnd};
-use rustc::hir::def::{Def, CtorKind};
-use rustc::hir::pat_util::EnumerateAndAdjustIterator;
-
-use rustc_data_structures::indexed_vec::Idx;
-use rustc_const_math::ConstFloat;
-
-use std::cmp::Ordering;
-use std::fmt;
-use syntax::ast;
-use syntax::ptr::P;
-use syntax_pos::Span;
-
-#[derive(Clone, Debug)]
-pub enum PatternError {
-    AssociatedConstInPattern(Span),
-    StaticInPattern(Span),
-    FloatBug,
-    NonConstPath(Span),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum BindingMode<'tcx> {
-    ByValue,
-    ByRef(Region<'tcx>, BorrowKind),
-}
-
-#[derive(Clone, Debug)]
-pub struct FieldPattern<'tcx> {
-    pub field: Field,
-    pub pattern: Pattern<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Pattern<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-    pub kind: Box<PatternKind<'tcx>>,
-}
-
-#[derive(Clone, Debug)]
-pub enum PatternKind<'tcx> {
-    Wild,
-
-    /// x, ref x, x @ P, etc
-    Binding {
-        mutability: Mutability,
-        name: ast::Name,
-        mode: BindingMode<'tcx>,
-        var: ast::NodeId,
-        ty: Ty<'tcx>,
-        subpattern: Option<Pattern<'tcx>>,
-    },
-
-    /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
-    Variant {
-        adt_def: &'tcx AdtDef,
-        substs: &'tcx Substs<'tcx>,
-        variant_index: usize,
-        subpatterns: Vec<FieldPattern<'tcx>>,
-    },
-
-    /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
-    Leaf {
-        subpatterns: Vec<FieldPattern<'tcx>>,
-    },
-
-    /// box P, &P, &mut P, etc
-    Deref {
-        subpattern: Pattern<'tcx>,
-    },
-
-    Constant {
-        value: &'tcx ty::Const<'tcx>,
-    },
-
-    Range {
-        lo: &'tcx ty::Const<'tcx>,
-        hi: &'tcx ty::Const<'tcx>,
-        end: RangeEnd,
-    },
-
-    /// matches against a slice, checking the length and extracting elements.
-    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
-    /// e.g. `&[ref xs..]`.
-    Slice {
-        prefix: Vec<Pattern<'tcx>>,
-        slice: Option<Pattern<'tcx>>,
-        suffix: Vec<Pattern<'tcx>>,
-    },
-
-    /// fixed match against an array, irrefutable
-    Array {
-        prefix: Vec<Pattern<'tcx>>,
-        slice: Option<Pattern<'tcx>>,
-        suffix: Vec<Pattern<'tcx>>,
-    },
-}
-
-fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
-    match value.val {
-        ConstVal::Value(v) => print_miri_value(v, value.ty, f),
-        ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
-    }
-}
-
-fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
-    use rustc::ty::TypeVariants::*;
-    match (value, &ty.sty) {
-        (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
-        (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
-        (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
-            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
-        _ => bug!("{:?}: {} not printable in a pattern", value, ty),
-    }
-}
-
-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 ")?;
-                        match bk { BorrowKind::Mut { .. } => true, _ => false }
-                    }
-                };
-                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 {
-                        if !adt.is_enum() {
-                            Some(&adt.variants[0])
-                        } else {
-                            None
-                        }
-                    } 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::TyAdt(def, _) if def.is_box() => 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 { value } => {
-                print_const_val(value, f)
-            }
-            PatternKind::Range { lo, hi, end } => {
-                print_const_val(lo, f)?;
-                match end {
-                    RangeEnd::Included => write!(f, "...")?,
-                    RangeEnd::Excluded => 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, 'tcx: 'a> {
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
-    pub tables: &'a ty::TypeckTables<'tcx>,
-    pub substs: &'tcx Substs<'tcx>,
-    pub errors: Vec<PatternError>,
-}
-
-impl<'a, 'tcx> Pattern<'tcx> {
-    pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
-                    tables: &'a ty::TypeckTables<'tcx>,
-                    pat: &'tcx hir::Pat) -> Self {
-        let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
-        let result = pcx.lower_pattern(pat);
-        if !pcx.errors.is_empty() {
-            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
-            tcx.sess.delay_span_bug(pat.span, &msg);
-        }
-        debug!("Pattern::from_hir({:?}) = {:?}", pat, result);
-        result
-    }
-}
-
-impl<'a, 'tcx> PatternContext<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
-               tables: &'a ty::TypeckTables<'tcx>) -> Self {
-        PatternContext {
-            tcx,
-            param_env: param_env_and_substs.param_env,
-            tables,
-            substs: param_env_and_substs.value,
-            errors: vec![]
-        }
-    }
-
-    pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
-        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
-        // pattern has the type that results *after* dereferencing. For example, in this code:
-        //
-        // ```
-        // match &&Some(0i32) {
-        //     Some(n) => { ... },
-        //     _ => { ... },
-        // }
-        // ```
-        //
-        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
-        // determined in rustc_typeck::check::match). The adjustments would be
-        //
-        // `vec![&&Option<i32>, &Option<i32>]`.
-        //
-        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
-        // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the
-        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
-        // gets the least-dereferenced type).
-        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
-        self.tables
-            .pat_adjustments()
-            .get(pat.hir_id)
-            .unwrap_or(&vec![])
-            .iter()
-            .rev()
-            .fold(unadjusted_pat, |pat, ref_ty| {
-                    debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
-                    Pattern {
-                        span: pat.span,
-                        ty: ref_ty,
-                        kind: Box::new(PatternKind::Deref { subpattern: pat }),
-                    }
-                },
-            )
-    }
-
-    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
-        let mut ty = self.tables.node_id_to_type(pat.hir_id);
-
-        let kind = match pat.node {
-            PatKind::Wild => PatternKind::Wild,
-
-            PatKind::Lit(ref value) => self.lower_lit(value),
-
-            PatKind::Range(ref lo_expr, ref hi_expr, end) => {
-                match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) {
-                    (PatternKind::Constant { value: lo },
-                     PatternKind::Constant { value: hi }) => {
-                        use std::cmp::Ordering;
-                        match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
-                            (RangeEnd::Excluded, Ordering::Less) => {},
-                            (RangeEnd::Excluded, _) => span_err!(
-                                self.tcx.sess,
-                                lo_expr.span,
-                                E0579,
-                                "lower range bound must be less than upper",
-                            ),
-                            (RangeEnd::Included, Ordering::Greater) => {
-                                struct_span_err!(self.tcx.sess, lo_expr.span, E0030,
-                                    "lower range bound must be less than or equal to upper")
-                                    .span_label(lo_expr.span, "lower bound larger than upper bound")
-                                    .emit();
-                            },
-                            (RangeEnd::Included, _) => {}
-                        }
-                        PatternKind::Range { lo, hi, end }
-                    }
-                    _ => PatternKind::Wild
-                }
-            }
-
-            PatKind::Path(ref qpath) => {
-                return self.lower_path(qpath, pat.hir_id, pat.span);
-            }
-
-            PatKind::Ref(ref subpattern, _) |
-            PatKind::Box(ref subpattern) => {
-                PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
-            }
-
-            PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                let ty = self.tables.node_id_to_type(pat.hir_id);
-                match ty.sty {
-                    ty::TyRef(_, mt) =>
-                        PatternKind::Deref {
-                            subpattern: Pattern {
-                                ty: mt.ty,
-                                span: pat.span,
-                                kind: Box::new(self.slice_or_array_pattern(
-                                    pat.span, mt.ty, prefix, slice, suffix))
-                            },
-                        },
-
-                    ty::TySlice(..) |
-                    ty::TyArray(..) =>
-                        self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
-
-                    ref sty =>
-                        span_bug!(
-                            pat.span,
-                            "unexpanded type for vector pattern: {:?}",
-                            sty),
-                }
-            }
-
-            PatKind::Tuple(ref subpatterns, ddpos) => {
-                let ty = self.tables.node_id_to_type(pat.hir_id);
-                match ty.sty {
-                    ty::TyTuple(ref tys, _) => {
-                        let subpatterns =
-                            subpatterns.iter()
-                                       .enumerate_and_adjust(tys.len(), ddpos)
-                                       .map(|(i, subpattern)| FieldPattern {
-                                            field: Field::new(i),
-                                            pattern: self.lower_pattern(subpattern)
-                                       })
-                                       .collect();
-
-                        PatternKind::Leaf { subpatterns: subpatterns }
-                    }
-
-                    ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty),
-                }
-            }
-
-            PatKind::Binding(_, id, ref ident, ref sub) => {
-                let var_ty = self.tables.node_id_to_type(pat.hir_id);
-                let region = match var_ty.sty {
-                    ty::TyRef(r, _) => Some(r),
-                    _ => None,
-                };
-                let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
-                                                         .expect("missing binding mode");
-                let (mutability, mode) = match bm {
-                    ty::BindByValue(hir::MutMutable) =>
-                        (Mutability::Mut, BindingMode::ByValue),
-                    ty::BindByValue(hir::MutImmutable) =>
-                        (Mutability::Not, BindingMode::ByValue),
-                    ty::BindByReference(hir::MutMutable) =>
-                        (Mutability::Not, BindingMode::ByRef(
-                            region.unwrap(), BorrowKind::Mut { allow_two_phase_borrow: false })),
-                    ty::BindByReference(hir::MutImmutable) =>
-                        (Mutability::Not, BindingMode::ByRef(
-                            region.unwrap(), BorrowKind::Shared)),
-                };
-
-                // A ref x pattern is the same node used for x, and as such it has
-                // x's type, which is &T, where we want T (the type being matched).
-                if let ty::BindByReference(_) = bm {
-                    if let ty::TyRef(_, mt) = ty.sty {
-                        ty = mt.ty;
-                    } else {
-                        bug!("`ref {}` has wrong type {}", ident.node, ty);
-                    }
-                }
-
-                PatternKind::Binding {
-                    mutability,
-                    mode,
-                    name: ident.node,
-                    var: id,
-                    ty: var_ty,
-                    subpattern: self.lower_opt_pattern(sub),
-                }
-            }
-
-            PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
-                let def = self.tables.qpath_def(qpath, pat.hir_id);
-                let adt_def = match ty.sty {
-                    ty::TyAdt(adt_def, _) => adt_def,
-                    _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
-                };
-                let variant_def = adt_def.variant_of_def(def);
-
-                let subpatterns =
-                        subpatterns.iter()
-                                   .enumerate_and_adjust(variant_def.fields.len(), ddpos)
-                                   .map(|(i, field)| FieldPattern {
-                                       field: Field::new(i),
-                                       pattern: self.lower_pattern(field),
-                                   })
-                                   .collect();
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
-            }
-
-            PatKind::Struct(ref qpath, ref fields, _) => {
-                let def = self.tables.qpath_def(qpath, pat.hir_id);
-                let adt_def = match ty.sty {
-                    ty::TyAdt(adt_def, _) => adt_def,
-                    _ => {
-                        span_bug!(
-                            pat.span,
-                            "struct pattern not applied to an ADT");
-                    }
-                };
-                let variant_def = adt_def.variant_of_def(def);
-
-                let subpatterns =
-                    fields.iter()
-                          .map(|field| {
-                              let index = variant_def.index_of_field_named(field.node.name);
-                              let index = index.unwrap_or_else(|| {
-                                  span_bug!(
-                                      pat.span,
-                                      "no field with name {:?}",
-                                      field.node.name);
-                              });
-                              FieldPattern {
-                                  field: Field::new(index),
-                                  pattern: self.lower_pattern(&field.node.pat),
-                              }
-                          })
-                          .collect();
-
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
-            }
-        };
-
-        Pattern {
-            span: pat.span,
-            ty,
-            kind: Box::new(kind),
-        }
-    }
-
-    fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
-        pats.iter().map(|p| self.lower_pattern(p)).collect()
-    }
-
-    fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
-    {
-        pat.as_ref().map(|p| self.lower_pattern(p))
-    }
-
-    fn flatten_nested_slice_patterns(
-        &mut self,
-        prefix: Vec<Pattern<'tcx>>,
-        slice: Option<Pattern<'tcx>>,
-        suffix: Vec<Pattern<'tcx>>)
-        -> (Vec<Pattern<'tcx>>, Option<Pattern<'tcx>>, Vec<Pattern<'tcx>>)
-    {
-        let orig_slice = match slice {
-            Some(orig_slice) => orig_slice,
-            None => return (prefix, slice, suffix)
-        };
-        let orig_prefix = prefix;
-        let orig_suffix = suffix;
-
-        // dance because of intentional borrow-checker stupidity.
-        let kind = *orig_slice.kind;
-        match kind {
-            PatternKind::Slice { prefix, slice, mut suffix } |
-            PatternKind::Array { prefix, slice, mut suffix } => {
-                let mut orig_prefix = orig_prefix;
-
-                orig_prefix.extend(prefix);
-                suffix.extend(orig_suffix);
-
-                (orig_prefix, slice, suffix)
-            }
-            _ => {
-                (orig_prefix, Some(Pattern {
-                    kind: box kind, ..orig_slice
-                }), orig_suffix)
-            }
-        }
-    }
-
-    fn slice_or_array_pattern(
-        &mut self,
-        span: Span,
-        ty: Ty<'tcx>,
-        prefix: &'tcx [P<hir::Pat>],
-        slice: &'tcx Option<P<hir::Pat>>,
-        suffix: &'tcx [P<hir::Pat>])
-        -> PatternKind<'tcx>
-    {
-        let prefix = self.lower_patterns(prefix);
-        let slice = self.lower_opt_pattern(slice);
-        let suffix = self.lower_patterns(suffix);
-        let (prefix, slice, suffix) =
-            self.flatten_nested_slice_patterns(prefix, slice, suffix);
-
-        match ty.sty {
-            ty::TySlice(..) => {
-                // matching a slice or fixed-length array
-                PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix }
-            }
-
-            ty::TyArray(_, len) => {
-                // fixed-length array
-                let len = len.val.unwrap_u64();
-                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
-                PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
-            }
-
-            _ => {
-                span_bug!(span, "bad slice pattern type {:?}", ty);
-            }
-        }
-    }
-
-    fn lower_variant_or_leaf(
-        &mut self,
-        def: Def,
-        span: Span,
-        ty: Ty<'tcx>,
-        subpatterns: Vec<FieldPattern<'tcx>>)
-        -> PatternKind<'tcx>
-    {
-        match def {
-            Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
-                let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
-                let adt_def = self.tcx.adt_def(enum_id);
-                if adt_def.is_enum() {
-                    let substs = match ty.sty {
-                        ty::TyAdt(_, substs) |
-                        ty::TyFnDef(_, substs) => substs,
-                        _ => bug!("inappropriate type for def: {:?}", ty.sty),
-                    };
-                    PatternKind::Variant {
-                        adt_def,
-                        substs,
-                        variant_index: adt_def.variant_index_with_id(variant_id),
-                        subpatterns,
-                    }
-                } else {
-                    PatternKind::Leaf { subpatterns: subpatterns }
-                }
-            }
-
-            Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
-            Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
-                PatternKind::Leaf { subpatterns: subpatterns }
-            }
-
-            _ => {
-                self.errors.push(PatternError::NonConstPath(span));
-                PatternKind::Wild
-            }
-        }
-    }
-
-    fn lower_path(&mut self,
-                  qpath: &hir::QPath,
-                  id: hir::HirId,
-                  span: Span)
-                  -> Pattern<'tcx> {
-        let ty = self.tables.node_id_to_type(id);
-        let def = self.tables.qpath_def(qpath, id);
-        let is_associated_const = match def {
-            Def::AssociatedConst(_) => true,
-            _ => false,
-        };
-        let kind = match def {
-            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                let substs = self.tables.node_substs(id);
-                match ty::Instance::resolve(
-                    self.tcx,
-                    self.param_env,
-                    def_id,
-                    substs,
-                ) {
-                    Some(instance) => {
-                        let cid = GlobalId {
-                            instance,
-                            promoted: None,
-                        };
-                        match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
-                            Ok(value) => {
-                                return self.const_to_pat(instance, value, id, span)
-                            },
-                            Err(err) => {
-                                err.report(self.tcx, span, "pattern");
-                                PatternKind::Wild
-                            },
-                        }
-                    },
-                    None => {
-                        self.errors.push(if is_associated_const {
-                            PatternError::AssociatedConstInPattern(span)
-                        } else {
-                            PatternError::StaticInPattern(span)
-                        });
-                        PatternKind::Wild
-                    },
-                }
-            }
-            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
-        };
-
-        Pattern {
-            span,
-            ty,
-            kind: Box::new(kind),
-        }
-    }
-
-    fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
-        match expr.node {
-            hir::ExprLit(ref lit) => {
-                let ty = self.tables.expr_ty(expr);
-                match lit_to_const(&lit.node, self.tcx, ty, false) {
-                    Ok(val) => {
-                        let instance = ty::Instance::new(
-                            self.tables.local_id_root.expect("literal outside any scope"),
-                            self.substs,
-                        );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
-                    },
-                    Err(()) => {
-                        self.errors.push(PatternError::FloatBug);
-                        PatternKind::Wild
-                    },
-                }
-            },
-            hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
-            hir::ExprUnary(hir::UnNeg, ref expr) => {
-                let ty = self.tables.expr_ty(expr);
-                let lit = match expr.node {
-                    hir::ExprLit(ref lit) => lit,
-                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
-                };
-                match lit_to_const(&lit.node, self.tcx, ty, true) {
-                    Ok(val) => {
-                        let instance = ty::Instance::new(
-                            self.tables.local_id_root.expect("literal outside any scope"),
-                            self.substs,
-                        );
-                        let cv = self.tcx.mk_const(ty::Const { val, ty });
-                        *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
-                    },
-                    Err(()) => {
-                        self.errors.push(PatternError::FloatBug);
-                        PatternKind::Wild
-                    },
-                }
-            }
-            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
-        }
-    }
-
-    fn const_to_pat(
-        &self,
-        instance: ty::Instance<'tcx>,
-        cv: &'tcx ty::Const<'tcx>,
-        id: hir::HirId,
-        span: Span,
-    ) -> Pattern<'tcx> {
-        debug!("const_to_pat: cv={:#?}", cv);
-        let kind = match cv.ty.sty {
-            ty::TyFloat(_) => {
-                let id = self.tcx.hir.hir_to_node_id(id);
-                self.tcx.lint_node(
-                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-                    id,
-                    span,
-                    "floating-point types cannot be used in patterns",
-                );
-                PatternKind::Constant {
-                    value: cv,
-                }
-            },
-            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");
-                PatternKind::Wild
-            }
-            ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
-                let msg = 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));
-                self.tcx.sess.span_err(span, &msg);
-                PatternKind::Wild
-            },
-            ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
-                match cv.val {
-                    ConstVal::Value(val) => {
-                        let discr = const_discr(
-                            self.tcx, self.param_env, instance, val, cv.ty
-                        ).unwrap();
-                        let variant_index = adt_def
-                            .discriminants(self.tcx)
-                            .position(|var| var.val == discr)
-                            .unwrap();
-                        PatternKind::Variant {
-                            adt_def,
-                            substs,
-                            variant_index,
-                            subpatterns: adt_def
-                                .variants[variant_index]
-                                .fields
-                                .iter()
-                                .enumerate()
-                                .map(|(i, _)| {
-                                let field = Field::new(i);
-                                let val = match cv.val {
-                                    ConstVal::Value(miri) => const_val_field(
-                                        self.tcx, self.param_env, instance,
-                                        Some(variant_index), field, miri, cv.ty,
-                                    ).unwrap(),
-                                    _ => bug!("{:#?} is not a valid tuple", cv),
-                                };
-                                FieldPattern {
-                                    field,
-                                    pattern: self.const_to_pat(instance, val, id, span),
-                                }
-                            }).collect(),
-                        }
-                    },
-                    _ => return Pattern {
-                        span,
-                        ty: cv.ty,
-                        kind: Box::new(PatternKind::Constant {
-                            value: cv,
-                        }),
-                    }
-                }
-            },
-            ty::TyAdt(adt_def, _) => {
-                let struct_var = adt_def.non_enum_variant();
-                PatternKind::Leaf {
-                    subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| {
-                        let field = Field::new(i);
-                        let val = match cv.val {
-                            ConstVal::Value(miri) => const_val_field(
-                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
-                            ).unwrap(),
-                            _ => bug!("{:#?} is not a valid tuple", cv),
-                        };
-                        FieldPattern {
-                            field,
-                            pattern: self.const_to_pat(instance, val, id, span),
-                        }
-                    }).collect()
-                }
-            }
-            ty::TyTuple(fields, _) => {
-                PatternKind::Leaf {
-                    subpatterns: (0..fields.len()).map(|i| {
-                        let field = Field::new(i);
-                        let val = match cv.val {
-                            ConstVal::Value(miri) => const_val_field(
-                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
-                            ).unwrap(),
-                            _ => bug!("{:#?} is not a valid tuple", cv),
-                        };
-                        FieldPattern {
-                            field,
-                            pattern: self.const_to_pat(instance, val, id, span),
-                        }
-                    }).collect()
-                }
-            }
-            ty::TyArray(_, n) => {
-                PatternKind::Array {
-                    prefix: (0..n.val.unwrap_u64()).map(|i| {
-                        let i = i as usize;
-                        let field = Field::new(i);
-                        let val = match cv.val {
-                            ConstVal::Value(miri) => const_val_field(
-                                self.tcx, self.param_env, instance, None, field, miri, cv.ty,
-                            ).unwrap(),
-                            _ => bug!("{:#?} is not a valid tuple", cv),
-                        };
-                        self.const_to_pat(instance, val, id, span)
-                    }).collect(),
-                    slice: None,
-                    suffix: Vec::new(),
-                }
-            }
-            _ => {
-                PatternKind::Constant {
-                    value: cv,
-                }
-            },
-        };
-
-        Pattern {
-            span,
-            ty: cv.ty,
-            kind: Box::new(kind),
-        }
-    }
-}
-
-pub trait PatternFoldable<'tcx> : Sized {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.super_fold_with(folder)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
-}
-
-pub trait PatternFolder<'tcx> : Sized {
-    fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> {
-        pattern.super_fold_with(self)
-    }
-
-    fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> {
-        kind.super_fold_with(self)
-    }
-}
-
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let content: T = (**self).fold_with(folder);
-        box content
-    }
-}
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|t| t.fold_with(folder)).collect()
-    }
-}
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self{
-        self.as_ref().map(|t| t.fold_with(folder))
-    }
-}
-
-macro_rules! CloneImpls {
-    (<$lt_tcx:tt> $($ty:ty),+) => {
-        $(
-            impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
-                fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
-                    Clone::clone(self)
-                }
-            }
-        )+
-    }
-}
-
-CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
-    Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
-}
-
-impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        FieldPattern {
-            field: self.field.fold_with(folder),
-            pattern: self.pattern.fold_with(folder)
-        }
-    }
-}
-
-impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_pattern(self)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Pattern {
-            ty: self.ty.fold_with(folder),
-            span: self.span.fold_with(folder),
-            kind: self.kind.fold_with(folder)
-        }
-    }
-}
-
-impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_pattern_kind(self)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            PatternKind::Wild => PatternKind::Wild,
-            PatternKind::Binding {
-                mutability,
-                name,
-                mode,
-                var,
-                ty,
-                ref subpattern,
-            } => PatternKind::Binding {
-                mutability: mutability.fold_with(folder),
-                name: name.fold_with(folder),
-                mode: mode.fold_with(folder),
-                var: var.fold_with(folder),
-                ty: ty.fold_with(folder),
-                subpattern: subpattern.fold_with(folder),
-            },
-            PatternKind::Variant {
-                adt_def,
-                substs,
-                variant_index,
-                ref subpatterns,
-            } => PatternKind::Variant {
-                adt_def: adt_def.fold_with(folder),
-                substs: substs.fold_with(folder),
-                variant_index: variant_index.fold_with(folder),
-                subpatterns: subpatterns.fold_with(folder)
-            },
-            PatternKind::Leaf {
-                ref subpatterns,
-            } => PatternKind::Leaf {
-                subpatterns: subpatterns.fold_with(folder),
-            },
-            PatternKind::Deref {
-                ref subpattern,
-            } => PatternKind::Deref {
-                subpattern: subpattern.fold_with(folder),
-            },
-            PatternKind::Constant {
-                value
-            } => PatternKind::Constant {
-                value: value.fold_with(folder)
-            },
-            PatternKind::Range {
-                lo,
-                hi,
-                end,
-            } => PatternKind::Range {
-                lo: lo.fold_with(folder),
-                hi: hi.fold_with(folder),
-                end,
-            },
-            PatternKind::Slice {
-                ref prefix,
-                ref slice,
-                ref suffix,
-            } => PatternKind::Slice {
-                prefix: prefix.fold_with(folder),
-                slice: slice.fold_with(folder),
-                suffix: suffix.fold_with(folder)
-            },
-            PatternKind::Array {
-                ref prefix,
-                ref slice,
-                ref suffix
-            } => PatternKind::Array {
-                prefix: prefix.fold_with(folder),
-                slice: slice.fold_with(folder),
-                suffix: suffix.fold_with(folder)
-            },
-        }
-    }
-}
-
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
-    use rustc_const_math::ConstFloat;
-    trace!("compare_const_vals: {:?}, {:?}", a, b);
-    use rustc::mir::interpret::{Value, PrimVal};
-    match (a, b) {
-        (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
-         &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
-            match ty.sty {
-                ty::TyFloat(ty) => {
-                    let l = ConstFloat {
-                        bits: a,
-                        ty,
-                    };
-                    let r = ConstFloat {
-                        bits: b,
-                        ty,
-                    };
-                    // FIXME(oli-obk): report cmp errors?
-                    l.try_cmp(r).ok()
-                },
-                ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
-                _ => Some(a.cmp(&b)),
-            }
-        },
-        _ if a == b => Some(Ordering::Equal),
-        _ => None,
-    }
-}
-
-fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty: Ty<'tcx>,
-                          neg: bool)
-                          -> Result<ConstVal<'tcx>, ()> {
-    use syntax::ast::*;
-
-    use rustc::mir::interpret::*;
-    let lit = match *lit {
-        LitKind::Str(ref s, _) => {
-            let s = s.as_str();
-            let id = tcx.allocate_cached(s.as_bytes());
-            let ptr = MemoryPointer::new(id, 0);
-            Value::ByValPair(
-                PrimVal::Ptr(ptr),
-                PrimVal::from_u128(s.len() as u128),
-            )
-        },
-        LitKind::ByteStr(ref data) => {
-            let id = tcx.allocate_cached(data);
-            let ptr = MemoryPointer::new(id, 0);
-            Value::ByVal(PrimVal::Ptr(ptr))
-        },
-        LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
-        LitKind::Int(n, _) => {
-            enum Int {
-                Signed(IntTy),
-                Unsigned(UintTy),
-            }
-            let ty = match ty.sty {
-                ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
-                ty::TyInt(other) => Int::Signed(other),
-                ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
-                ty::TyUint(other) => Int::Unsigned(other),
-                _ => bug!(),
-            };
-            let n = match ty {
-                // FIXME(oli-obk): are these casts correct?
-                Int::Signed(IntTy::I8) if neg =>
-                    (n as i128 as i8).overflowing_neg().0 as i128 as u128,
-                Int::Signed(IntTy::I16) if neg =>
-                    (n as i128 as i16).overflowing_neg().0 as i128 as u128,
-                Int::Signed(IntTy::I32) if neg =>
-                    (n as i128 as i32).overflowing_neg().0 as i128 as u128,
-                Int::Signed(IntTy::I64) if neg =>
-                    (n as i128 as i64).overflowing_neg().0 as i128 as u128,
-                Int::Signed(IntTy::I128) if neg =>
-                    (n as i128).overflowing_neg().0 as u128,
-                Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
-                Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
-                Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
-                Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
-                Int::Signed(IntTy::I128) => n,
-                Int::Unsigned(UintTy::U8) => n as u8 as u128,
-                Int::Unsigned(UintTy::U16) => n as u16 as u128,
-                Int::Unsigned(UintTy::U32) => n as u32 as u128,
-                Int::Unsigned(UintTy::U64) => n as u64 as u128,
-                Int::Unsigned(UintTy::U128) => n,
-                _ => bug!(),
-            };
-            Value::ByVal(PrimVal::Bytes(n))
-        },
-        LitKind::Float(n, fty) => {
-            let n = n.as_str();
-            let mut f = parse_float(&n, fty)?;
-            if neg {
-                f = -f;
-            }
-            let bits = f.bits;
-            Value::ByVal(PrimVal::Bytes(bits))
-        }
-        LitKind::FloatUnsuffixed(n) => {
-            let fty = match ty.sty {
-                ty::TyFloat(fty) => fty,
-                _ => bug!()
-            };
-            let n = n.as_str();
-            let mut f = parse_float(&n, fty)?;
-            if neg {
-                f = -f;
-            }
-            let bits = f.bits;
-            Value::ByVal(PrimVal::Bytes(bits))
-        }
-        LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
-        LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
-    };
-    Ok(ConstVal::Value(lit))
-}
-
-fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
-                     -> Result<ConstFloat, ()> {
-    ConstFloat::from_str(num, fty).map_err(|_| ())
-}