about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-10-25 07:07:08 +0000
committerbors <bors@rust-lang.org>2014-10-25 07:07:08 +0000
commita34b8dec697014f15e725215e17ea8d956c0ab1a (patch)
treec0a34067e63f5fb5602926eedc82f453fa16335e /src
parent172b59abe510dde5826fec24377f208a19418c04 (diff)
parent1484f9cd46013a227d1d057508ff57ebc5930a8d (diff)
downloadrust-a34b8dec697014f15e725215e17ea8d956c0ab1a.tar.gz
rust-a34b8dec697014f15e725215e17ea8d956c0ab1a.zip
auto merge of #18171 : jakub-/rust/match-typeck, r=pcwalton
Rather than doing it top-down, with a known expected type, we will now simply establish the appropriate constraints between the pattern and the expression it destructures.

Closes #8783.
Closes #10200.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/diagnostics.rs2
-rw-r--r--src/librustc/metadata/decoder.rs11
-rw-r--r--src/librustc/middle/privacy.rs17
-rw-r--r--src/librustc/middle/resolve.rs1
-rw-r--r--src/librustc/middle/ty.rs11
-rw-r--r--src/librustc/middle/typeck/check/_match.rs1050
-rw-r--r--src/librustc/middle/typeck/check/mod.rs6
-rw-r--r--src/librustc/middle/typeck/collect.rs5
-rw-r--r--src/test/compile-fail/destructure-trait-ref.rs12
-rw-r--r--src/test/compile-fail/issue-10200.rs19
-rw-r--r--src/test/compile-fail/issue-13482.rs3
-rw-r--r--src/test/compile-fail/issue-13624.rs3
-rw-r--r--src/test/compile-fail/issue-14541.rs4
-rw-r--r--src/test/compile-fail/issue-15260.rs22
-rw-r--r--src/test/compile-fail/issue-15896.rs4
-rw-r--r--src/test/compile-fail/issue-16338.rs3
-rw-r--r--src/test/compile-fail/issue-16401.rs3
-rw-r--r--src/test/compile-fail/issue-17405.rs2
-rw-r--r--src/test/compile-fail/issue-17800.rs2
-rw-r--r--src/test/compile-fail/issue-5100.rs13
-rw-r--r--src/test/compile-fail/issue-7092.rs5
-rw-r--r--src/test/compile-fail/match-vec-mismatch-2.rs3
-rw-r--r--src/test/compile-fail/pattern-error-continue.rs3
-rw-r--r--src/test/compile-fail/suppressed-error.rs3
-rw-r--r--src/test/run-pass/issue-8783.rs30
25 files changed, 490 insertions, 747 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index c392d92a83f..601a9a73c3d 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -44,11 +44,9 @@ register_diagnostics!(
     E0025,
     E0026,
     E0027,
-    E0028,
     E0029,
     E0030,
     E0031,
-    E0032,
     E0033,
     E0034,
     E0035,
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index e1205ae1f76..fd71e4f7b1f 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -673,9 +673,14 @@ pub fn get_enum_variants(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
         let ctor_ty = item_type(ast::DefId { krate: cdata.cnum, node: id},
                                 item, tcx, cdata);
         let name = item_name(&*intr, item);
-        let arg_tys = match ty::get(ctor_ty).sty {
-            ty::ty_bare_fn(ref f) => f.sig.inputs.clone(),
-            _ => Vec::new(), // Nullary enum variant.
+        let (ctor_ty, arg_tys) = match ty::get(ctor_ty).sty {
+            ty::ty_bare_fn(ref f) =>
+                (Some(ctor_ty), f.sig.inputs.clone()),
+            _ => // Nullary or struct enum variant.
+                (None, get_struct_fields(intr.clone(), cdata, did.node)
+                    .iter()
+                    .map(|field_ty| get_type(cdata, field_ty.id.node, tcx).ty)
+                    .collect())
         };
         match variant_disr_val(item) {
             Some(val) => { disr_val = val; }
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 7f429bef129..2256bd71e65 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -667,21 +667,12 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
 
         let struct_type = ty::lookup_item_type(self.tcx, id).ty;
         let struct_desc = match ty::get(struct_type).sty {
-            ty::ty_struct(_, _) => format!("struct `{}`", ty::item_path_str(self.tcx, id)),
-            ty::ty_bare_fn(ty::BareFnTy { sig: ty::FnSig { output, .. }, .. }) => {
-                // Struct `id` is really a struct variant of an enum,
-                // and we're really looking at the variant's constructor
-                // function. So get the return type for a detailed error
-                // message.
-                let enum_id = match ty::get(output).sty {
-                    ty::ty_enum(id, _) => id,
-                    _ => self.tcx.sess.span_bug(span, "enum variant doesn't \
-                                                       belong to an enum")
-                };
+            ty::ty_struct(_, _) =>
+                format!("struct `{}`", ty::item_path_str(self.tcx, id)),
+            ty::ty_enum(enum_id, _) =>
                 format!("variant `{}` of enum `{}`",
                         ty::with_path(self.tcx, id, |mut p| p.last().unwrap()),
-                        ty::item_path_str(self.tcx, enum_id))
-            }
+                        ty::item_path_str(self.tcx, enum_id)),
             _ => self.tcx.sess.span_bug(span, "can't find struct for field")
         };
         let msg = match name {
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 9c06ddca7e8..fad4ef4f15f 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5077,7 +5077,6 @@ impl<'a> Resolver<'a> {
                 PatEnum(ref path, _) => {
                     // This must be an enum variant, struct or const.
                     match self.resolve_path(pat_id, path, ValueNS, false) {
-                        Some(def @ (DefFn(..), _))      |
                         Some(def @ (DefVariant(..), _)) |
                         Some(def @ (DefStruct(..), _))  |
                         Some(def @ (DefConst(..), _)) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index c54f2aec12d..8c602548f33 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -50,7 +50,7 @@ use syntax::ast::{CrateNum, DefId, FnStyle, Ident, ItemTrait, LOCAL_CRATE};
 use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
 use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
 use syntax::ast::{Visibility};
-use syntax::ast_util::{mod, PostExpansionMethod, is_local, lit_is_str};
+use syntax::ast_util::{mod, is_local, lit_is_str, local_def, PostExpansionMethod};
 use syntax::attr::{mod, AttrMetaMethods};
 use syntax::codemap::Span;
 use syntax::parse::token::{mod, InternedString};
@@ -4221,7 +4221,7 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
 pub struct VariantInfo {
     pub args: Vec<t>,
     pub arg_names: Option<Vec<ast::Ident> >,
-    pub ctor_ty: t,
+    pub ctor_ty: Option<t>,
     pub name: ast::Name,
     pub id: ast::DefId,
     pub disr_val: Disr,
@@ -4249,7 +4249,7 @@ impl VariantInfo {
                 return VariantInfo {
                     args: arg_tys,
                     arg_names: None,
-                    ctor_ty: ctor_ty,
+                    ctor_ty: Some(ctor_ty),
                     name: ast_variant.node.name.name,
                     id: ast_util::local_def(ast_variant.node.id),
                     disr_val: discriminant,
@@ -4262,7 +4262,8 @@ impl VariantInfo {
 
                 assert!(fields.len() > 0);
 
-                let arg_tys = ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
+                let arg_tys = struct_def.fields.iter()
+                    .map(|field| node_id_to_type(cx, field.node.id)).collect();
                 let arg_names = fields.iter().map(|field| {
                     match field.node.kind {
                         NamedField(ident, _) => ident,
@@ -4274,7 +4275,7 @@ impl VariantInfo {
                 return VariantInfo {
                     args: arg_tys,
                     arg_names: Some(arg_names),
-                    ctor_ty: ctor_ty,
+                    ctor_ty: None,
                     name: ast_variant.node.name.name,
                     id: ast_util::local_def(ast_variant.node.id),
                     disr_val: discriminant,
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index 94ae9561990..14725c581c8 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -8,29 +8,229 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_camel_case_types)]
-
 use middle::def;
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
-use middle::subst;
-use middle::subst::Subst;
+use middle::subst::{Subst, Substs};
 use middle::ty;
-use middle::typeck::check::demand;
-use middle::typeck::check::{check_expr, check_expr_has_type, FnCtxt};
-use middle::typeck::check::{instantiate_path, lookup_def};
-use middle::typeck::check::{structure_of, valid_range_bounds};
-use middle::typeck::infer;
+use middle::typeck::check::{check_expr, check_expr_has_type, demand, FnCtxt};
+use middle::typeck::check::{instantiate_path, structurally_resolved_type, valid_range_bounds};
+use middle::typeck::infer::{mod, resolve};
 use middle::typeck::require_same_types;
-use util::ppaux;
 
-use std::collections::{HashMap, HashSet};
+use std::cmp;
+use std::collections::HashMap;
+use std::collections::hashmap::{Occupied, Vacant};
 use syntax::ast;
 use syntax::ast_util;
-use syntax::parse::token;
 use syntax::codemap::{Span, Spanned};
+use syntax::parse::token;
 use syntax::print::pprust;
 use syntax::ptr::P;
 
+pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
+    let fcx = pcx.fcx;
+    let tcx = pcx.fcx.ccx.tcx;
+
+    match pat.node {
+        ast::PatWild(_) => {
+            fcx.write_ty(pat.id, expected);
+        }
+        ast::PatLit(ref lt) => {
+            check_expr(fcx, &**lt);
+            let expr_ty = fcx.expr_ty(&**lt);
+            fcx.write_ty(pat.id, expr_ty);
+            demand::suptype(fcx, pat.span, expected, expr_ty);
+        }
+        ast::PatRange(ref begin, ref end) => {
+            check_expr(fcx, &**begin);
+            check_expr(fcx, &**end);
+
+            let lhs_ty = fcx.expr_ty(&**begin);
+            let rhs_ty = fcx.expr_ty(&**end);
+            if require_same_types(
+                tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty,
+                || "mismatched types in range".to_string())
+                && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(rhs_ty)) {
+                match valid_range_bounds(fcx.ccx, &**begin, &**end) {
+                    Some(false) => {
+                        span_err!(tcx.sess, begin.span, E0030,
+                            "lower range bound must be less than upper");
+                    },
+                    None => {
+                        span_err!(tcx.sess, begin.span, E0031,
+                            "mismatched types in range");
+                    },
+                    Some(true) => {}
+                }
+            } else {
+                span_err!(tcx.sess, begin.span, E0029,
+                    "only char and numeric types are allowed in range");
+            }
+
+            fcx.write_ty(pat.id, lhs_ty);
+            demand::eqtype(fcx, pat.span, expected, lhs_ty);
+        }
+        ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
+            let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
+            let const_pty = ty::lookup_item_type(tcx, const_did);
+            fcx.write_ty(pat.id, const_pty.ty);
+            demand::eqtype(fcx, pat.span, expected, const_pty.ty);
+        }
+        ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
+            let typ = fcx.local_ty(pat.span, pat.id);
+            match bm {
+                ast::BindByRef(mutbl) => {
+                    // if the binding is like
+                    //    ref x | ref const x | ref mut x
+                    // then the type of x is &M T where M is the mutability
+                    // and T is the expected type
+                    let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    let mt = ty::mt { ty: expected, mutbl: mutbl };
+                    let region_ty = ty::mk_rptr(tcx, region_var, mt);
+                    demand::eqtype(fcx, pat.span, region_ty, typ);
+                }
+                // otherwise the type of x is the expected type T
+                ast::BindByValue(_) => {
+                    demand::eqtype(fcx, pat.span, expected, typ);
+                }
+            }
+            fcx.write_ty(pat.id, typ);
+
+            let canon_id = pcx.map[path.node];
+            if canon_id != pat.id {
+                let ct = fcx.local_ty(pat.span, canon_id);
+                demand::eqtype(fcx, pat.span, ct, typ);
+            }
+
+            if let Some(ref p) = *sub {
+                check_pat(pcx, &**p, expected);
+            }
+        }
+        ast::PatIdent(_, ref path, _) => {
+            let path = ast_util::ident_to_path(path.span, path.node);
+            check_pat_enum(pcx, pat, &path, &Some(vec![]), expected);
+        }
+        ast::PatEnum(ref path, ref subpats) => {
+            check_pat_enum(pcx, pat, path, subpats, expected);
+        }
+        ast::PatStruct(ref path, ref fields, etc) => {
+            check_pat_struct(pcx, pat, path, fields.as_slice(), etc, expected);
+        }
+        ast::PatTup(ref elements) => {
+            let element_tys = Vec::from_fn(elements.len(), |_| fcx.infcx().next_ty_var());
+            let pat_ty = ty::mk_tup(tcx, element_tys.clone());
+            fcx.write_ty(pat.id, pat_ty);
+            demand::eqtype(fcx, pat.span, expected, pat_ty);
+            for (element_pat, element_ty) in elements.iter().zip(element_tys.into_iter()) {
+                check_pat(pcx, &**element_pat, element_ty);
+            }
+        }
+        ast::PatBox(ref inner) => {
+            let inner_ty = fcx.infcx().next_ty_var();
+            let uniq_ty = ty::mk_uniq(tcx, inner_ty);
+
+            if check_dereferencable(pcx, pat.span, expected, &**inner) {
+                demand::suptype(fcx, pat.span, expected, uniq_ty);
+                fcx.write_ty(pat.id, uniq_ty);
+                check_pat(pcx, &**inner, inner_ty);
+            } else {
+                fcx.write_error(pat.id);
+                check_pat(pcx, &**inner, ty::mk_err());
+            }
+        }
+        ast::PatRegion(ref inner) => {
+            let inner_ty = fcx.infcx().next_ty_var();
+
+            let mutbl = infer::resolve_type(
+                fcx.infcx(), Some(pat.span),
+                expected, resolve::try_resolve_tvar_shallow)
+                .ok()
+                .and_then(|t| ty::deref(t, true))
+                .map_or(ast::MutImmutable, |mt| mt.mutbl);
+
+            let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
+            let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+            let rptr_ty = ty::mk_rptr(tcx, region, mt);
+
+            if check_dereferencable(pcx, pat.span, expected, &**inner) {
+                demand::suptype(fcx, pat.span, expected, rptr_ty);
+                fcx.write_ty(pat.id, rptr_ty);
+                check_pat(pcx, &**inner, inner_ty);
+            } else {
+                fcx.write_error(pat.id);
+                check_pat(pcx, &**inner, ty::mk_err());
+            }
+        }
+        ast::PatVec(ref before, ref slice, ref after) => {
+            let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
+            let inner_ty = fcx.infcx().next_ty_var();
+            let pat_ty = match ty::get(expected_ty).sty {
+                ty::ty_vec(_, Some(size)) => ty::mk_vec(tcx, inner_ty, Some({
+                    let min_len = before.len() + after.len();
+                    match *slice {
+                        Some(_) => cmp::max(min_len, size),
+                        None => min_len
+                    }
+                })),
+                _ => {
+                    let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                    ty::mk_slice(tcx, region, ty::mt {
+                        ty: inner_ty,
+                        mutbl: ty::deref(expected_ty, true)
+                            .map_or(ast::MutImmutable, |mt| mt.mutbl)
+                    })
+                }
+            };
+
+            fcx.write_ty(pat.id, pat_ty);
+            demand::suptype(fcx, pat.span, expected, pat_ty);
+
+            for elt in before.iter() {
+                check_pat(pcx, &**elt, inner_ty);
+            }
+            if let Some(ref slice) = *slice {
+                let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                let mutbl = ty::deref(expected_ty, true)
+                    .map_or(ast::MutImmutable, |mt| mt.mutbl);
+
+                let slice_ty = ty::mk_slice(tcx, region, ty::mt {
+                    ty: inner_ty,
+                    mutbl: mutbl
+                });
+                check_pat(pcx, &**slice, slice_ty);
+            }
+            for elt in after.iter() {
+                check_pat(pcx, &**elt, inner_ty);
+            }
+        }
+        ast::PatMac(_) => tcx.sess.bug("unexpanded macro")
+    }
+}
+
+pub fn check_dereferencable(pcx: &pat_ctxt, span: Span, expected: ty::t,
+                            inner: &ast::Pat) -> bool {
+    let fcx = pcx.fcx;
+    let tcx = pcx.fcx.ccx.tcx;
+    match infer::resolve_type(
+        fcx.infcx(), Some(span),
+        expected, resolve::try_resolve_tvar_shallow) {
+        Ok(t) if pat_is_binding(&tcx.def_map, inner) => {
+            ty::deref(t, true).map_or(true, |mt| match ty::get(mt.ty).sty {
+                ty::ty_trait(_) => {
+                    // This is "x = SomeTrait" being reduced from
+                    // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
+                    span_err!(tcx.sess, span, E0033,
+                        "type `{}` cannot be dereferenced",
+                        fcx.infcx().ty_to_string(t));
+                    false
+                }
+                _ => true
+            })
+        }
+        _ => true
+    }
+}
+
 pub fn check_match(fcx: &FnCtxt,
                    expr: &ast::Expr,
                    discrim: &ast::Expr,
@@ -47,10 +247,13 @@ pub fn check_match(fcx: &FnCtxt,
             fcx: fcx,
             map: pat_id_map(&tcx.def_map, &*arm.pats[0]),
         };
-
-        for p in arm.pats.iter() { check_pat(&mut pcx, &**p, discrim_ty);}
+        for p in arm.pats.iter() {
+            check_pat(&mut pcx, &**p, discrim_ty);
+        }
     }
 
+    // Now typecheck the blocks.
+    //
     // The result of the match is the common supertype of all the
     // arms. Start out the value as bottom, since it's the, well,
     // bottom the type lattice, and we'll be moving up the lattice as
@@ -58,51 +261,26 @@ pub fn check_match(fcx: &FnCtxt,
     // on any empty type and is therefore unreachable; should the flow
     // of execution reach it, we will fail, so bottom is an appropriate
     // type in that case)
-    let mut result_ty = ty::mk_bot();
-
-    // Now typecheck the blocks.
-    let mut saw_err = ty::type_is_error(discrim_ty);
-    for arm in arms.iter() {
-        let mut guard_err = false;
-        let mut guard_bot = false;
-        match arm.guard {
-            Some(ref e) => {
-                check_expr_has_type(fcx, &**e, ty::mk_bool());
-                let e_ty = fcx.expr_ty(&**e);
-                if ty::type_is_error(e_ty) {
-                    guard_err = true;
-                }
-                else if ty::type_is_bot(e_ty) {
-                    guard_bot = true;
-                }
-            },
-            None => ()
-        }
+    let result_ty = arms.iter().fold(ty::mk_bot(), |result_ty, arm| {
         check_expr(fcx, &*arm.body);
         let bty = fcx.node_ty(arm.body.id);
-        saw_err = saw_err || ty::type_is_error(bty);
-        if guard_err {
-            fcx.write_error(arm.body.id);
-            saw_err = true;
-        }
-        else if guard_bot {
-            fcx.write_bot(arm.body.id);
+
+        if let Some(ref e) = arm.guard {
+            check_expr_has_type(fcx, &**e, ty::mk_bool());
         }
 
-        result_ty =
+        if ty::type_is_error(result_ty) || ty::type_is_error(bty) {
+            ty::mk_err()
+        } else {
             infer::common_supertype(
                 fcx.infcx(),
                 infer::MatchExpressionArm(expr.span, arm.body.span),
                 true, // result_ty is "expected" here
                 result_ty,
-                bty);
-    }
-
-    if saw_err {
-        result_ty = ty::mk_err();
-    } else if ty::type_is_bot(discrim_ty) {
-        result_ty = ty::mk_bot();
-    }
+                bty
+            )
+        }
+    });
 
     fcx.write_ty(expr.id, result_ty);
 }
@@ -112,173 +290,120 @@ pub struct pat_ctxt<'a, 'tcx: 'a> {
     pub map: PatIdMap,
 }
 
-pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
-                         subpats: &Option<Vec<P<ast::Pat>>>, expected: ty::t) {
-
-    // Typecheck the path.
+pub fn check_pat_struct(pcx: &pat_ctxt, pat: &ast::Pat,
+                        path: &ast::Path, fields: &[Spanned<ast::FieldPat>],
+                        etc: bool, expected: ty::t) {
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    let arg_types: Vec<ty::t> ;
-    let kind_name;
-
-    // structure_of requires type variables to be resolved.
-    // So when we pass in <expected>, it's an error if it
-    // contains type variables.
-
-    // Check to see whether this is an enum or a struct.
-    match *structure_of(pcx.fcx, pat.span, expected) {
-        ty::ty_enum(expected_def_id, ref expected_substs) => {
-            // Lookup the enum and variant def ids:
-            let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
-            match v_def.variant_def_ids() {
-                Some((enm, var)) => {
-                    // Assign the pattern the type of the *enum*, not the variant.
-                    let enum_pty = ty::lookup_item_type(tcx, enm);
-                    instantiate_path(pcx.fcx,
-                                     path,
-                                     enum_pty,
-                                     v_def,
-                                     pat.span,
-                                     pat.id);
-
-                    // check that the type of the value being matched is a subtype
-                    // of the type of the pattern:
-                    let pat_ty = fcx.node_ty(pat.id);
-                    demand::subtype(fcx, pat.span, expected, pat_ty);
-
-                    // Get the expected types of the arguments.
-                    arg_types = {
-                        let vinfo =
-                            ty::enum_variant_with_id(tcx, enm, var);
-                        if enm == expected_def_id {
-                            vinfo.args.iter()
-                                .map(|t| t.subst(tcx, expected_substs))
-                                .collect()
-                        } else {
-                            vinfo.args.iter()
-                                .map(|_| ty::mk_err())
-                                .collect()
-                        }
-                    };
-
-                    kind_name = "variant";
-                }
-                None => {
-                    // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-                    fcx.infcx().type_error_message_str_with_expected(pat.span,
-                                                       |expected, actual| {
-                       expected.map_or("".to_string(), |e| {
-                        format!("mismatched types: expected `{}`, found {}",
-                                e, actual)
-                        })},
-                        Some(expected),
-                        "a structure pattern".to_string(),
-                        None);
-                    fcx.write_error(pat.id);
-                    kind_name = "[error]";
-                    arg_types = subpats.clone()
-                                       .unwrap_or_default()
-                                       .into_iter()
-                                       .map(|_| ty::mk_err())
-                                       .collect();
-                }
-            }
-        }
-        ty::ty_struct(struct_def_id, ref expected_substs) => {
-            // Lookup the struct ctor def id
-            let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
-            let s_def_id = s_def.def_id();
-
-            // Assign the pattern the type of the struct.
-            let ctor_pty = ty::lookup_item_type(tcx, s_def_id);
-            let struct_pty = if ty::is_fn_ty(ctor_pty.ty) {
-                ty::Polytype {ty: ty::ty_fn_ret(ctor_pty.ty),
-                              ..ctor_pty}
-            } else {
-                ctor_pty
-            };
-            instantiate_path(pcx.fcx,
-                             path,
-                             struct_pty,
-                             s_def,
-                             pat.span,
-                             pat.id);
-
-            // Check that the type of the value being matched is a subtype of
-            // the type of the pattern.
-            let pat_ty = fcx.node_ty(pat.id);
-            demand::subtype(fcx, pat.span, expected, pat_ty);
-
-            // Get the expected types of the arguments.
-            let class_fields = ty::struct_fields(
-                tcx, struct_def_id, expected_substs);
-            arg_types = class_fields.iter().map(|field| field.mt.ty).collect();
-
-            kind_name = "structure";
-        }
+    let def = tcx.def_map.borrow().get_copy(&pat.id);
+    let def_type = ty::lookup_item_type(tcx, def.def_id());
+    let (enum_def_id, variant_def_id) = match ty::get(def_type.ty).sty {
+        ty::ty_struct(struct_def_id, _) =>
+            (struct_def_id, struct_def_id),
+        ty::ty_enum(enum_def_id, _) if def == def::DefVariant(enum_def_id, def.def_id(), true) =>
+            (enum_def_id, def.def_id()),
         _ => {
-            // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-            fcx.infcx().type_error_message_str_with_expected(pat.span,
-                                               |expected, actual| {
-                                               expected.map_or("".to_string(),
-                                                              |e| {
-                        format!("mismatched types: expected `{}`, found {}",
-                                e, actual)
-                    })
-                },
-                Some(expected),
-                "an enum or structure pattern".to_string(),
-                None);
+            let name = pprust::path_to_string(path);
+            span_err!(tcx.sess, pat.span, E0163,
+                "`{}` does not name a struct or a struct variant", name);
             fcx.write_error(pat.id);
-            kind_name = "[error]";
-            arg_types = subpats.clone()
-                               .unwrap_or_default()
-                               .iter()
-                               .map(|_| ty::mk_err())
-                               .collect();
+
+            for field in fields.iter() {
+                check_pat(pcx, &*field.node.pat, ty::mk_err());
+            }
+            return;
         }
-    }
+    };
 
-    let arg_len = arg_types.len();
+    instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id),
+                     def, pat.span, pat.id);
 
-    // Count the number of subpatterns.
-    let subpats_len;
-    match *subpats {
-        None => subpats_len = arg_len,
-        Some(ref subpats) => subpats_len = subpats.len()
-    }
+    let pat_ty = fcx.node_ty(pat.id);
+    demand::eqtype(fcx, pat.span, expected, pat_ty);
 
-    let mut error_happened = false;
+    let item_substs = fcx
+        .item_substs()
+        .find(&pat.id)
+        .map(|substs| substs.substs.clone())
+        .unwrap_or_else(|| Substs::empty());
 
-    if arg_len > 0 {
-        // N-ary variant.
-        if arg_len != subpats_len {
-            span_err!(tcx.sess, pat.span, E0023,
-                      "this pattern has {} field{}, but the corresponding {} has {} field{}",
-                      subpats_len, if subpats_len == 1 {""} else {"s"},
-                      kind_name, arg_len, if arg_len == 1 {""} else {"s"});
-            error_happened = true;
+    let struct_fields = ty::struct_fields(tcx, variant_def_id, &item_substs);
+    check_struct_pat_fields(pcx, pat.span, fields, struct_fields.as_slice(),
+                            variant_def_id, etc);
+}
+
+pub fn check_pat_enum(pcx: &pat_ctxt, pat: &ast::Pat,
+                      path: &ast::Path, subpats: &Option<Vec<P<ast::Pat>>>,
+                      expected: ty::t) {
+
+    // Typecheck the path.
+    let fcx = pcx.fcx;
+    let tcx = pcx.fcx.ccx.tcx;
+
+    let def = tcx.def_map.borrow().get_copy(&pat.id);
+    let enum_def = def.variant_def_ids()
+        .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
+
+    let ctor_pty = ty::lookup_item_type(tcx, enum_def);
+    let path_ty = if ty::is_fn_ty(ctor_pty.ty) {
+        ty::Polytype { ty: ty::ty_fn_ret(ctor_pty.ty), ..ctor_pty }
+    } else {
+        ctor_pty
+    };
+    instantiate_path(pcx.fcx, path, path_ty, def, pat.span, pat.id);
+
+    let pat_ty = fcx.node_ty(pat.id);
+    demand::eqtype(fcx, pat.span, expected, pat_ty);
+
+    let real_path_ty = fcx.node_ty(pat.id);
+    let (arg_tys, kind_name) = match ty::get(real_path_ty).sty {
+        ty::ty_enum(enum_def_id, ref expected_substs) => {
+            let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id());
+            (variant.args.iter().map(|t| t.subst(tcx, expected_substs)).collect::<Vec<_>>(),
+                "variant")
+        }
+        ty::ty_struct(struct_def_id, ref expected_substs) => {
+            let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs);
+            (struct_fields.iter().map(|field| field.mt.ty).collect::<Vec<_>>(),
+                "struct")
         }
+        _ => {
+            let name = pprust::path_to_string(path);
+            span_err!(tcx.sess, pat.span, E0164,
+                "`{}` does not name a variant or a tuple struct", name);
+            fcx.write_error(pat.id);
 
-        if !error_happened {
-            for pats in subpats.iter() {
-                for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
-                    check_pat(pcx, &**subpat, *arg_ty);
+            if let Some(ref subpats) = *subpats {
+                for pat in subpats.iter() {
+                    check_pat(pcx, &**pat, ty::mk_err());
                 }
             }
+            return;
         }
-    } else if subpats_len > 0 {
-        span_err!(tcx.sess, pat.span, E0024,
-                  "this pattern has {} field{}, but the corresponding {} has no fields",
-                  subpats_len, if subpats_len == 1 {""} else {"s"},
-                  kind_name);
-        error_happened = true;
-    }
+    };
+
+    if let Some(ref subpats) = *subpats {
+        if subpats.len() == arg_tys.len() {
+            for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) {
+                check_pat(pcx, &**subpat, *arg_ty);
+            }
+        } else if arg_tys.len() == 0 {
+            span_err!(tcx.sess, pat.span, E0024,
+                      "this pattern has {} field{}, but the corresponding {} has no fields",
+                      subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
 
-    if error_happened {
-        for pats in subpats.iter() {
-            for pat in pats.iter() {
+            for pat in subpats.iter() {
+                check_pat(pcx, &**pat, ty::mk_err());
+            }
+        } else {
+            span_err!(tcx.sess, pat.span, E0023,
+                      "this pattern has {} field{}, but the corresponding {} has {} field{}",
+                      subpats.len(), if subpats.len() == 1 {""} else {"s"},
+                      kind_name,
+                      arg_tys.len(), if arg_tys.len() == 1 {""} else {"s"});
+
+            for pat in subpats.iter() {
                 check_pat(pcx, &**pat, ty::mk_err());
             }
         }
@@ -287,515 +412,62 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
 
 /// `path` is the AST path item naming the type of this struct.
 /// `fields` is the field patterns of the struct pattern.
-/// `class_fields` describes the type of each field of the struct.
-/// `class_id` is the ID of the struct.
-/// `substitutions` are the type substitutions applied to this struct type
-/// (e.g. K,V in HashMap<K,V>).
+/// `struct_fields` describes the type of each field of the struct.
+/// `struct_id` is the ID of the struct.
 /// `etc` is true if the pattern said '...' and false otherwise.
 pub fn check_struct_pat_fields(pcx: &pat_ctxt,
                                span: Span,
                                fields: &[Spanned<ast::FieldPat>],
-                               class_fields: Vec<ty::field_ty>,
-                               class_id: ast::DefId,
-                               substitutions: &subst::Substs,
+                               struct_fields: &[ty::field],
+                               struct_id: ast::DefId,
                                etc: bool) {
     let tcx = pcx.fcx.ccx.tcx;
 
-    // Index the class fields. The second argument in the tuple is whether the
-    // field has been bound yet or not.
-    let mut field_map = HashMap::new();
-    for (i, class_field) in class_fields.iter().enumerate() {
-        field_map.insert(class_field.name, (i, false));
-    }
+    // Index the struct fields' types.
+    let field_type_map = struct_fields
+        .iter()
+        .map(|field| (field.name, field.mt.ty))
+        .collect::<HashMap<_, _>>();
+
+    // Keep track of which fields have already appeared in the pattern.
+    let mut used_fields = HashMap::new();
 
     // Typecheck each field.
-    let mut found_fields = HashSet::new();
     for &Spanned { node: ref field, span } in fields.iter() {
-        match field_map.find_mut(&field.ident.name) {
-            Some(&(_, true)) => {
-                // Check the pattern anyway, so that attempts to look
-                // up its type won't fail
-                check_pat(pcx, &*field.pat, ty::mk_err());
+        let field_type = match used_fields.entry(field.ident.name) {
+            Occupied(occupied) => {
                 span_err!(tcx.sess, span, E0025,
-                    "field `{}` bound twice in pattern",
+                    "field `{}` bound multiple times in the pattern",
                     token::get_ident(field.ident));
-            }
-            Some(&(index, ref mut used)) => {
-                *used = true;
-                let class_field = class_fields[index].clone();
-                let field_type = ty::lookup_field_type(tcx,
-                                                       class_id,
-                                                       class_field.id,
-                                                       substitutions);
-                check_pat(pcx, &*field.pat, field_type);
-                found_fields.insert(index);
-            }
-            None => {
-                // Check the pattern anyway, so that attempts to look
-                // up its type won't fail
-                check_pat(pcx, &*field.pat, ty::mk_err());
-                span_err!(tcx.sess, span, E0026,
-                    "struct `{}` does not have a field named `{}`",
-                    ty::item_path_str(tcx, class_id),
+                span_note!(tcx.sess, *occupied.get(),
+                    "field `{}` previously bound here",
                     token::get_ident(field.ident));
+                ty::mk_err()
             }
-        }
+            Vacant(vacant) => {
+                vacant.set(span);
+                field_type_map.find_copy(&field.ident.name)
+                    .unwrap_or_else(|| {
+                        span_err!(tcx.sess, span, E0026,
+                            "struct `{}` does not have a field named `{}`",
+                            ty::item_path_str(tcx, struct_id),
+                            token::get_ident(field.ident));
+                        ty::mk_err()
+                    })
+            }
+        };
+
+        check_pat(pcx, &*field.pat, field_type);
     }
 
     // Report an error if not all the fields were specified.
     if !etc {
-        for (i, field) in class_fields.iter().enumerate() {
-            if found_fields.contains(&i) {
-                continue;
-            }
+        for field in struct_fields
+            .iter()
+            .filter(|field| !used_fields.contains_key(&field.name)) {
             span_err!(tcx.sess, span, E0027,
                 "pattern does not mention field `{}`",
                 token::get_name(field.name));
         }
     }
 }
-
-pub fn check_struct_pat(pcx: &pat_ctxt, span: Span,
-                        fields: &[Spanned<ast::FieldPat>], etc: bool,
-                        struct_id: ast::DefId,
-                        substitutions: &subst::Substs) {
-    let _fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
-
-    let class_fields = ty::lookup_struct_fields(tcx, struct_id);
-
-    check_struct_pat_fields(pcx, span, fields, class_fields, struct_id,
-                            substitutions, etc);
-}
-
-pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
-                                          pat_id: ast::NodeId,
-                                          span: Span,
-                                          expected: ty::t,
-                                          path: &ast::Path,
-                                          fields: &[Spanned<ast::FieldPat>],
-                                          etc: bool,
-                                          enum_id: ast::DefId,
-                                          substitutions: &subst::Substs) {
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
-
-    // Find the variant that was specified.
-    match tcx.def_map.borrow().find(&pat_id) {
-        Some(&def::DefVariant(found_enum_id, variant_id, true))
-                if found_enum_id == enum_id => {
-            // Get the struct fields from this struct-like enum variant.
-            let struct_fields = ty::lookup_struct_fields(tcx, variant_id);
-            check_struct_pat_fields(pcx, span, fields, struct_fields,
-                                    variant_id, substitutions, etc);
-            fcx.write_ty(pat_id, expected);
-        }
-        Some(&def::DefVariant(_, _, false)) => {
-            let name = pprust::path_to_string(path);
-            span_err!(tcx.sess, span, E0163,
-                "`{}` does not name a struct variant", name);
-            fcx.write_error(pat_id);
-        }
-        Some(&def::DefVariant(_, _, true)) => {
-            let name = pprust::path_to_string(path);
-            span_err!(tcx.sess, span, E0164,
-                "`{}` does not name a variant of the type being matched against", name);
-            fcx.write_error(pat_id);
-        }
-        Some(&def::DefStruct(..)) |
-        Some(&def::DefTy(..)) => {
-            let name = pprust::path_to_string(path);
-            span_err!(tcx.sess, span, E0028,
-                "`{}` does not name a variant", name);
-            fcx.write_error(pat_id);
-        }
-        _ => {
-            tcx.sess.span_bug(span, "resolve didn't write in variant");
-        }
-    }
-
-    if ty::type_is_error(fcx.node_ty(pat_id)) {
-        for field in fields.iter() {
-            check_pat(pcx, &*field.node.pat, ty::mk_err());
-        }
-    }
-}
-
-// Pattern checking is top-down rather than bottom-up so that bindings get
-// their types immediately.
-pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
-    let fcx = pcx.fcx;
-    let tcx = pcx.fcx.ccx.tcx;
-
-    match pat.node {
-      ast::PatWild(_) => {
-        fcx.write_ty(pat.id, expected);
-      }
-      ast::PatLit(ref lt) => {
-        check_expr_has_type(fcx, &**lt, expected);
-        fcx.write_ty(pat.id, fcx.expr_ty(&**lt));
-      }
-      ast::PatRange(ref begin, ref end) => {
-        check_expr_has_type(fcx, &**begin, expected);
-        check_expr_has_type(fcx, &**end, expected);
-        let b_ty =
-            fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**begin));
-        let e_ty =
-            fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**end));
-        debug!("pat_range beginning type: {}", b_ty);
-        debug!("pat_range ending type: {}", e_ty);
-        if !require_same_types(
-            tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
-            || "mismatched types in range".to_string())
-        {
-            // no-op
-        } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
-            span_err!(tcx.sess, begin.span, E0029,
-                "only char and numeric types are allowed in range");
-        } else {
-            match valid_range_bounds(fcx.ccx, &**begin, &**end) {
-                Some(false) => {
-                    span_err!(tcx.sess, begin.span, E0030,
-                        "lower range bound must be less than upper");
-                },
-                None => {
-                    span_err!(tcx.sess, begin.span, E0031,
-                        "mismatched types in range");
-                },
-                _ => { },
-            }
-        }
-        fcx.write_ty(pat.id, b_ty);
-      }
-      ast::PatEnum(..) |
-      ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
-        let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
-        let const_pty = ty::lookup_item_type(tcx, const_did);
-        demand::suptype(fcx, pat.span, expected, const_pty.ty);
-        fcx.write_ty(pat.id, const_pty.ty);
-      }
-      ast::PatIdent(bm, ref path1, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
-        let typ = fcx.local_ty(pat.span, pat.id);
-
-        match bm {
-          ast::BindByRef(mutbl) => {
-            // if the binding is like
-            //    ref x | ref const x | ref mut x
-            // then the type of x is &M T where M is the mutability
-            // and T is the expected type
-            let region_var =
-                fcx.infcx().next_region_var(
-                    infer::PatternRegion(pat.span));
-            let mt = ty::mt {ty: expected, mutbl: mutbl};
-            let region_ty = ty::mk_rptr(tcx, region_var, mt);
-            demand::eqtype(fcx, pat.span, region_ty, typ);
-          }
-          // otherwise the type of x is the expected type T
-          ast::BindByValue(_) => {
-            demand::eqtype(fcx, pat.span, expected, typ);
-          }
-        }
-
-        let canon_id = pcx.map[path1.node];
-        if canon_id != pat.id {
-            let ct = fcx.local_ty(pat.span, canon_id);
-            demand::eqtype(fcx, pat.span, ct, typ);
-        }
-        fcx.write_ty(pat.id, typ);
-
-        debug!("(checking match) writing type {} (expected {}) for pat id {}",
-               ppaux::ty_to_string(tcx, typ),
-               ppaux::ty_to_string(tcx, expected),
-               pat.id);
-
-        match *sub {
-            Some(ref p) => check_pat(pcx, &**p, expected),
-            _ => ()
-        }
-      }
-      // it's not a binding, it's an enum in disguise:
-      ast::PatIdent(_, ref path1, _) => {
-        let path = ast_util::ident_to_path(path1.span,path1.node);
-        check_pat_variant(pcx, pat, &path, &Some(Vec::new()), expected);
-      }
-      ast::PatEnum(ref path, ref subpats) => {
-        check_pat_variant(pcx, pat, path, subpats, expected);
-      }
-      ast::PatStruct(ref path, ref fields, etc) => {
-        // Grab the class data that we care about.
-        let structure = structure_of(fcx, pat.span, expected);
-        let mut error_happened = false;
-        match *structure {
-            ty::ty_struct(cid, ref substs) => {
-                // Verify that the pattern named the right structure.
-                let item_did = (*tcx.def_map.borrow())[pat.id].def_id();
-                match ty::ty_to_def_id(ty::lookup_item_type(tcx, item_did).ty) {
-                    Some(struct_did) if struct_did != cid => {
-                        span_err!(tcx.sess, path.span, E0032,
-                                  "`{}` does not name the structure `{}`",
-                                  pprust::path_to_string(path),
-                                  fcx.infcx().ty_to_string(expected));
-                    },
-                    Some(_) => {},
-                    None => {
-                        tcx.sess.span_bug(
-                            path.span,
-                            format!("This shouldn't happen: failed to lookup structure. \
-                                item_did = {}", item_did).as_slice())
-                    },
-                }
-
-                check_struct_pat(pcx, pat.span, fields.as_slice(), etc, cid, substs);
-            }
-            ty::ty_enum(eid, ref substs) => {
-                check_struct_like_enum_variant_pat(pcx,
-                                                   pat.id,
-                                                   pat.span,
-                                                   expected,
-                                                   path,
-                                                   fields.as_slice(),
-                                                   etc,
-                                                   eid,
-                                                   substs);
-            }
-            _ => {
-               // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-                fcx.infcx().type_error_message_str_with_expected(pat.span,
-                                                                |expected, actual| {
-                            expected.map_or("".to_string(),
-                                            |e| {
-                                format!("mismatched types: expected \
-                                        `{}`, found {}", e, actual)
-                            })},
-                            Some(expected),
-                            "a structure pattern".to_string(),
-                            None);
-                match tcx.def_map.borrow().find(&pat.id) {
-                    Some(def) => {
-                        let struct_ty = fcx.instantiate_item_type(pat.span, def.def_id());
-                        check_struct_pat(pcx, pat.span, fields.as_slice(),
-                                         etc, def.def_id(), &struct_ty.substs);
-                    }
-                    None => {
-                        tcx.sess.span_bug(pat.span,
-                                          "whoops, looks like resolve didn't \
-                                           write a def in here")
-                    }
-                }
-                error_happened = true;
-            }
-        }
-
-        // Finally, write in the type.
-        if error_happened {
-            fcx.write_error(pat.id);
-        } else {
-            fcx.write_ty(pat.id, expected);
-        }
-      }
-      ast::PatTup(ref elts) => {
-        let s = structure_of(fcx, pat.span, expected);
-        let e_count = elts.len();
-        match *s {
-            ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
-                for (i, elt) in elts.iter().enumerate() {
-                    check_pat(pcx, &**elt, ex_elts[i]);
-                }
-                fcx.write_ty(pat.id, expected);
-            }
-            _ => {
-                for elt in elts.iter() {
-                    check_pat(pcx, &**elt, ty::mk_err());
-                }
-                // use terr_tuple_size if both types are tuples
-                let type_error = match *s {
-                    ty::ty_tup(ref ex_elts) => {
-                        ty::terr_tuple_size(ty::expected_found {
-                            expected: ex_elts.len(),
-                            found: e_count
-                        })
-                    }
-                    _ => ty::terr_mismatch
-                };
-                // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-                fcx.infcx().type_error_message_str_with_expected(pat.span,
-                                                                 |expected,
-                                                                  actual| {
-                        expected.map_or("".to_string(), |e| {
-                            format!("mismatched types: expected `{}`, \
-                                     found {}", e, actual)
-                        }
-                    )},
-                    Some(expected),
-                    "tuple".to_string(),
-                    Some(&type_error));
-                fcx.write_error(pat.id);
-            }
-        }
-      }
-      ast::PatBox(ref inner) => {
-          check_pointer_pat(pcx, Send, &**inner, pat.id, pat.span, expected);
-      }
-      ast::PatRegion(ref inner) => {
-          check_pointer_pat(pcx, Borrowed, &**inner, pat.id, pat.span, expected);
-      }
-      ast::PatVec(ref before, ref slice, ref after) => {
-        let default_region_var =
-            fcx.infcx().next_region_var(
-                infer::PatternRegion(pat.span));
-
-        let check_err = |found: String| {
-            for elt in before.iter() {
-                check_pat(pcx, &**elt, ty::mk_err());
-            }
-            for elt in slice.iter() {
-                check_pat(pcx, &**elt, ty::mk_err());
-            }
-            for elt in after.iter() {
-                check_pat(pcx, &**elt, ty::mk_err());
-            }
-            // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-            fcx.infcx().type_error_message_str_with_expected(
-                pat.span,
-                |expected, actual| {
-                    expected.map_or("".to_string(),
-                                    |e| {
-                        format!("mismatched types: expected `{}`, found {}",
-                                e, actual)
-                    })
-                },
-                Some(expected),
-                found,
-                None);
-            fcx.write_error(pat.id);
-        };
-
-        let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
-                                                                pat.span,
-                                                                expected) {
-          ty::ty_vec(ty, Some(fixed)) =>
-            (ty, default_region_var, ast::MutImmutable, Some(fixed)),
-          ty::ty_uniq(t) => match ty::get(t).sty {
-              ty::ty_vec(ty, None) => {
-                  fcx.type_error_message(pat.span,
-                                         |_| {
-                                            "unique vector patterns are no \
-                                             longer supported".to_string()
-                                         },
-                                         expected,
-                                         None);
-                  (ty, default_region_var, ast::MutImmutable, None)
-              }
-              _ => {
-                  check_err("an array  pattern".to_string());
-                  return;
-              }
-          },
-          ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
-              ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None),
-              _ => {
-                  check_err("an array pattern".to_string());
-                  return;
-              }
-          },
-          _ => {
-              check_err("an array pattern".to_string());
-              return;
-          }
-        };
-
-        let min_len = before.len() + after.len();
-        fixed.and_then(|count| match *slice {
-            Some(_) if count < min_len =>
-                Some(format!("a fixed array pattern of size at least {}", min_len)),
-
-            None if count != min_len =>
-                Some(format!("a fixed array pattern of size {}", min_len)),
-
-            _ => None
-        }).map(check_err);
-
-        for elt in before.iter() {
-            check_pat(pcx, &**elt, elt_type);
-        }
-        match *slice {
-            Some(ref slice_pat) => {
-                let slice_ty = ty::mk_slice(tcx,
-                                            region_var,
-                                            ty::mt {ty: elt_type, mutbl: mutbl});
-                check_pat(pcx, &**slice_pat, slice_ty);
-            }
-            None => ()
-        }
-        for elt in after.iter() {
-            check_pat(pcx, &**elt, elt_type);
-        }
-        fcx.write_ty(pat.id, expected);
-      }
-
-      ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
-    }
-}
-
-// Helper function to check gc, box and & patterns
-fn check_pointer_pat(pcx: &pat_ctxt,
-                     pointer_kind: PointerKind,
-                     inner: &ast::Pat,
-                     pat_id: ast::NodeId,
-                     span: Span,
-                     expected: ty::t) {
-    let fcx = pcx.fcx;
-    let tcx = fcx.ccx.tcx;
-    let check_inner: |ty::t| = |e_inner| {
-        match ty::get(e_inner).sty {
-            ty::ty_trait(_) if pat_is_binding(&tcx.def_map, inner) => {
-                // This is "x = SomeTrait" being reduced from
-                // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
-                check_pat(pcx, inner, ty::mk_err());
-                span_err!(tcx.sess, span, E0033,
-                    "type `{}` cannot be dereferenced",
-                    fcx.infcx().ty_to_string(expected));
-                fcx.write_error(pat_id);
-            }
-            _ => {
-                check_pat(pcx, inner, e_inner);
-                fcx.write_ty(pat_id, expected);
-            }
-        }
-    };
-
-    match *structure_of(fcx, span, expected) {
-        ty::ty_uniq(e_inner) if pointer_kind == Send => {
-            check_inner(e_inner);
-        }
-        ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
-            check_inner(e_inner.ty);
-        }
-        _ => {
-            check_pat(pcx, inner, ty::mk_err());
-            // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
-            fcx.infcx().type_error_message_str_with_expected(
-                span,
-                |expected, actual| {
-                    expected.map_or("".to_string(), |e| {
-                        format!("mismatched types: expected `{}`, found {}",
-                                e, actual)
-                    })
-                },
-                Some(expected),
-                format!("{} pattern", match pointer_kind {
-                    Send => "a box",
-                    Borrowed => "an `&`-pointer",
-                }),
-                None);
-            fcx.write_error(pat_id);
-          }
-    }
-}
-
-#[deriving(PartialEq)]
-pub enum PointerKind {
-    Send,
-    Borrowed,
-}
-
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 736ebb8244a..5ad68544570 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -117,7 +117,7 @@ use util::ppaux;
 use util::ppaux::{UserString, Repr};
 use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
 
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, Ref, RefCell};
 use std::collections::HashMap;
 use std::collections::hashmap::{Occupied, Vacant};
 use std::mem::replace;
@@ -1815,6 +1815,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn item_substs<'a>(&'a self) -> Ref<'a, NodeMap<ty::ItemSubsts>> {
+        self.inh.item_substs.borrow()
+    }
+
     pub fn opt_node_ty_substs(&self,
                               id: ast::NodeId,
                               f: |&ty::ItemSubsts|) {
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index a3339f217ce..1f4b80b360b 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -236,10 +236,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
                 };
 
                 convert_struct(ccx, &**struct_def, pty, variant.node.id);
-
-                let input_tys: Vec<_> = struct_def.fields.iter().map(
-                    |f| ty::node_id_to_type(ccx.tcx, f.node.id)).collect();
-                ty::mk_ctor_fn(tcx, scope, input_tys.as_slice(), enum_ty)
+                enum_ty
             }
         };
 
diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs
index 27aa43638f4..a2a5a3e257f 100644
--- a/src/test/compile-fail/destructure-trait-ref.rs
+++ b/src/test/compile-fail/destructure-trait-ref.rs
@@ -30,12 +30,12 @@ fn main() {
     let &&x = &&(&1i as &T);
 
     // n == m
-    let &x = &1i as &T;      //~ ERROR cannot be dereferenced
-    let &&x = &(&1i as &T);  //~ ERROR cannot be dereferenced
-    let box x = box 1i as Box<T>; //~ ERROR cannot be dereferenced
+    let &x = &1i as &T;      //~ ERROR type `&T` cannot be dereferenced
+    let &&x = &(&1i as &T);  //~ ERROR type `&T` cannot be dereferenced
+    let box x = box 1i as Box<T>; //~ ERROR type `Box<T>` cannot be dereferenced
 
     // n > m
-    let &&x = &1i as &T;     //~ ERROR found an `&`-pointer pattern
-    let &&&x = &(&1i as &T); //~ ERROR found an `&`-pointer pattern
-    let box box x = box 1i as Box<T>;    //~ ERROR found a box pattern
+    let &&x = &1i as &T;     //~ ERROR found &-ptr
+    let &&&x = &(&1i as &T); //~ ERROR found &-ptr
+    let box box x = box 1i as Box<T>;    //~ ERROR found box
 }
diff --git a/src/test/compile-fail/issue-10200.rs b/src/test/compile-fail/issue-10200.rs
new file mode 100644
index 00000000000..2b9ac705f32
--- /dev/null
+++ b/src/test/compile-fail/issue-10200.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 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.
+
+struct Foo(bool);
+fn foo(_: uint) -> Foo { Foo(false) }
+
+fn main() {
+    match Foo(true) {
+        foo(x) //~ ERROR `foo` is not an enum variant, struct or const
+        => ()
+    }
+}
diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs
index 2c7b56f9dc7..43c7f45e15a 100644
--- a/src/test/compile-fail/issue-13482.rs
+++ b/src/test/compile-fail/issue-13482.rs
@@ -12,7 +12,8 @@ fn main() {
   let x = [1,2];
   let y = match x {
     [] => None,
-//~^ ERROR expected `[<generic integer #0>, ..2]`, found a fixed array pattern of size 0
+//~^ ERROR mismatched types: expected `[<generic integer #0>, ..2]`, found `[<generic #7>, ..0]`
+//         (expected array, found array)
     [a,_] => Some(a)
   };
 }
diff --git a/src/test/compile-fail/issue-13624.rs b/src/test/compile-fail/issue-13624.rs
index 0593b498192..0c103515981 100644
--- a/src/test/compile-fail/issue-13624.rs
+++ b/src/test/compile-fail/issue-13624.rs
@@ -29,7 +29,8 @@ mod b {
       let enum_struct_variant = ::a::get_enum_struct_variant();
       match enum_struct_variant {
         a::EnumStructVariant { x, y, z } => {
-        //~^ ERROR error: mismatched types: expected `()`, found a structure pattern
+        //~^ ERROR mismatched types: expected `()`, found `a::Enum`
+        //         (expected (), found enum a::Enum)
         }
       }
     }
diff --git a/src/test/compile-fail/issue-14541.rs b/src/test/compile-fail/issue-14541.rs
index 921e331e960..ac49f8b99cf 100644
--- a/src/test/compile-fail/issue-14541.rs
+++ b/src/test/compile-fail/issue-14541.rs
@@ -13,8 +13,8 @@ struct vec3 { y: f32, z: f32 }
 
 fn make(v: vec2) {
     let vec3 { y: _, z: _ } = v;
-    //~^ ERROR `vec3` does not name the structure `vec2`
-    //~^^ ERROR struct `vec2` does not have a field named `z`
+    //~^ ERROR mismatched types: expected `vec2`, found `vec3`
+    //         (expected struct vec2, found struct vec3)
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-15260.rs b/src/test/compile-fail/issue-15260.rs
index 06826139884..e3d19729710 100644
--- a/src/test/compile-fail/issue-15260.rs
+++ b/src/test/compile-fail/issue-15260.rs
@@ -9,11 +9,23 @@
 // except according to those terms.
 
 struct Foo {
-  a: uint,
+    a: uint,
 }
 
-fn main(){
-    let Foo {a: _, a: _} = Foo {a: 29};
-    //~^ ERROR field `a` bound twice in pattern
-}
+fn main() {
+    let Foo {
+        a: _, //~ NOTE field `a` previously bound here
+        a: _ //~ ERROR field `a` bound multiple times in the pattern
+    } = Foo { a: 29 };
+
+    let Foo {
+        a, //~ NOTE field `a` previously bound here
+        a: _ //~ ERROR field `a` bound multiple times in the pattern
+    } = Foo { a: 29 };
 
+    let Foo {
+        a, //~ NOTE field `a` previously bound here
+        a: _, //~ ERROR field `a` bound multiple times in the pattern
+        a: x //~ ERROR field `a` bound multiple times in the pattern
+    } = Foo { a: 29 };
+}
diff --git a/src/test/compile-fail/issue-15896.rs b/src/test/compile-fail/issue-15896.rs
index b7fa54e5c18..5d92208d3e3 100644
--- a/src/test/compile-fail/issue-15896.rs
+++ b/src/test/compile-fail/issue-15896.rs
@@ -18,7 +18,9 @@ fn main() {
     let e = B(REB(()), Tau { t: 3 });
     let u = match e {
         B(
-          Tau{t: x}, //~ ERROR `Tau` does not name a variant
+          Tau{t: x},
+          //~^ ERROR mismatched types: expected `main::R`, found `main::Tau`
+          //        (expected enum main::R, found struct main::Tau)
           _) => x,
     };
 }
diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs
index 305b1fe2ad7..537fc5aaa55 100644
--- a/src/test/compile-fail/issue-16338.rs
+++ b/src/test/compile-fail/issue-16338.rs
@@ -12,6 +12,7 @@ use std::raw::Slice;
 
 fn main() {
     let Slice { data: data, len: len } = "foo";
-    //~^ ERROR mismatched types: expected `&str`, found a structure pattern
+    //~^ ERROR mismatched types: expected `&str`, found `core::raw::Slice<<generic #3>>`
+    //         (expected &-ptr, found struct core::raw::Slice)
 }
 
diff --git a/src/test/compile-fail/issue-16401.rs b/src/test/compile-fail/issue-16401.rs
index bece4381e41..deb2f5912b6 100644
--- a/src/test/compile-fail/issue-16401.rs
+++ b/src/test/compile-fail/issue-16401.rs
@@ -13,7 +13,8 @@ use std::raw::Slice;
 fn main() {
     match () {
         Slice { data: data, len: len } => (),
-        //~^ ERROR mismatched types: expected `()`, found a structure pattern
+        //~^ ERROR mismatched types: expected `()`, found `core::raw::Slice<<generic #3>>`
+        //         (expected (), found struct core::raw::Slice)
         _ => unreachable!()
     }
 }
diff --git a/src/test/compile-fail/issue-17405.rs b/src/test/compile-fail/issue-17405.rs
index b80cfb521ef..b0f2e0b666e 100644
--- a/src/test/compile-fail/issue-17405.rs
+++ b/src/test/compile-fail/issue-17405.rs
@@ -14,6 +14,6 @@ enum Foo {
 
 fn main() {
     match Bar(1i) {
-        Foo { i } => () //~ ERROR `Foo` does not name a variant
+        Foo { i } => () //~ ERROR `Foo` does not name a struct or a struct variant
     }
 }
diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs
index 8ef016e3fd5..30a8a51ed8c 100644
--- a/src/test/compile-fail/issue-17800.rs
+++ b/src/test/compile-fail/issue-17800.rs
@@ -15,7 +15,7 @@ enum MyOption<T> {
 
 fn main() {
     match MySome(42i) {
-        MySome { x: 42i } => (), //~ ERROR `MySome` does not name a struct variant
+        MySome { x: 42i } => (), //~ ERROR `MySome` does not name a struct or a struct variant
         _ => (),
     }
 }
diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs
index 5c4127c5bae..6524056df88 100644
--- a/src/test/compile-fail/issue-5100.rs
+++ b/src/test/compile-fail/issue-5100.rs
@@ -12,24 +12,29 @@ enum A { B, C }
 
 fn main() {
     match (true, false) {
-        B => (), //~ ERROR expected `(bool,bool)`, found an enum or structure pattern
+        B => (),
+        //~^ ERROR mismatched types: expected `(bool,bool)`, found `A`
+        //         (expected tuple, found enum A)
         _ => ()
     }
 
     match (true, false) {
         (true, false, false) => ()
-        //~^ ERROR mismatched types: expected `(bool,bool)`, found tuple
+        //~^ ERROR mismatched types: expected `(bool,bool)`,
+        //         found `(<generic #7>,<generic #8>,<generic #9>)`
         //         (expected a tuple with 2 elements, found one with 3 elements)
     }
 
     match (true, false) {
         box (true, false) => ()
-        //~^ ERROR mismatched types: expected `(bool,bool)`, found a box pattern
+        //~^ ERROR mismatched types: expected `(bool,bool)`, found `Box<<generic #11>>`
+        //         (expected tuple, found box)
     }
 
     match (true, false) {
         &(true, false) => ()
-        //~^ ERROR mismatched types: expected `(bool,bool)`, found an `&`-pointer pattern
+        //~^ ERROR mismatched types: expected `(bool,bool)`, found `&<generic #15>`
+        //         (expected tuple, found &-ptr)
     }
 
 
diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs
index 8b3df6f9f95..cc7e8052920 100644
--- a/src/test/compile-fail/issue-7092.rs
+++ b/src/test/compile-fail/issue-7092.rs
@@ -13,8 +13,9 @@ enum Whatever {
 
 fn foo(x: Whatever) {
     match x {
-        Some(field) => field.access(),
-        //~^ ERROR: mismatched types: expected `Whatever`, found
+        Some(field) =>
+//~^ ERROR: mismatched types: expected `Whatever`, found `core::option::Option<<generic #3>>`
+            field.access(), //~ ERROR the type of this value must be known in this context
     }
 }
 
diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs
index e095c7c2408..6d37eb8a636 100644
--- a/src/test/compile-fail/match-vec-mismatch-2.rs
+++ b/src/test/compile-fail/match-vec-mismatch-2.rs
@@ -10,6 +10,7 @@
 
 fn main() {
     match () {
-        [()] => { } //~ ERROR mismatched types: expected `()`, found an array pattern
+        [()] => { }
+//~^ ERROR mismatched types: expected `()`, found `&[<generic #1>]` (expected (), found &-ptr)
     }
 }
diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs
index 01feda34e08..f438f9973cf 100644
--- a/src/test/compile-fail/pattern-error-continue.rs
+++ b/src/test/compile-fail/pattern-error-continue.rs
@@ -29,7 +29,8 @@ fn main() {
         _ => ()
     }
     match 'c' {
-        S { .. } => (),   //~ ERROR mismatched types: expected `char`, found a structure pattern
+        S { .. } => (),
+        //~^ ERROR mismatched types: expected `char`, found `S` (expected char, found struct S)
 
         _ => ()
     }
diff --git a/src/test/compile-fail/suppressed-error.rs b/src/test/compile-fail/suppressed-error.rs
index f13aabe5259..54d6fa5bdd3 100644
--- a/src/test/compile-fail/suppressed-error.rs
+++ b/src/test/compile-fail/suppressed-error.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    let (x, y) = (); //~ ERROR expected `()`, found tuple (types differ)
+    let (x, y) = ();
+//~^ ERROR types: expected `()`, found `(<generic #3>,<generic #4>)` (expected (), found tuple)
     return x;
 }
diff --git a/src/test/run-pass/issue-8783.rs b/src/test/run-pass/issue-8783.rs
new file mode 100644
index 00000000000..d59c0ad52e9
--- /dev/null
+++ b/src/test/run-pass/issue-8783.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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 std::default::Default;
+
+struct X { pub x: uint }
+impl Default for X {
+    fn default() -> X {
+        X { x: 42u }
+    }
+}
+
+struct Y<T> { pub y: T }
+impl<T: Default> Default for Y<T> {
+    fn default() -> Y<T> {
+        Y { y: Default::default() }
+    }
+}
+
+fn main() {
+    let X { x: _ } = Default::default();
+    let Y { y: X { x } } = Default::default();
+}