about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/check_match.rs1073
-rw-r--r--src/librustc/middle/trans/_match.rs25
-rw-r--r--src/librustc/middle/typeck/check/_match.rs35
-rw-r--r--src/test/compile-fail/issue-13482.rs18
-rw-r--r--src/test/compile-fail/issue-2111.rs3
-rw-r--r--src/test/compile-fail/issue-4321.rs18
-rw-r--r--src/test/compile-fail/non-exhaustive-match-nested.rs3
-rw-r--r--src/test/compile-fail/non-exhaustive-match.rs17
-rw-r--r--src/test/compile-fail/non-exhaustive-pattern-witness.rs74
-rw-r--r--src/test/compile-fail/precise-refutable-pattern-errors.rs32
-rw-r--r--src/test/compile-fail/refutable-pattern-errors.rs18
-rw-r--r--src/test/compile-fail/refutable-pattern-in-fn-arg.rs3
-rw-r--r--src/test/run-pass/issue-14393.rs19
-rw-r--r--src/test/run-pass/issue-7784.rs36
14 files changed, 728 insertions, 646 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index d8f7a97ce13..6d8b178ba00 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -10,23 +10,57 @@
 
 #![allow(non_camel_case_types)]
 
-use middle::const_eval::{compare_const_vals, lookup_const_by_id};
-use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float};
+use middle::const_eval::{compare_const_vals, const_bool, const_float, const_val};
+use middle::const_eval::{eval_const_expr, lookup_const_by_id};
 use middle::def::*;
 use middle::pat_util::*;
 use middle::ty::*;
 use middle::ty;
-use util::ppaux::ty_to_str;
 
-use std::cmp;
 use std::gc::{Gc, GC};
 use std::iter;
 use syntax::ast::*;
 use syntax::ast_util::{is_unguarded, walk_pat};
-use syntax::codemap::{DUMMY_SP, Span};
-use syntax::parse::token;
+use syntax::codemap::{Span, Spanned, DUMMY_SP};
+use syntax::owned_slice::OwnedSlice;
+use syntax::print::pprust::pat_to_str;
 use syntax::visit;
 use syntax::visit::{Visitor, FnKind};
+use util::ppaux::ty_to_str;
+
+type Matrix = Vec<Vec<Gc<Pat>>>;
+
+#[deriving(Clone)]
+enum Usefulness {
+    Useful(Vec<Gc<Pat>>),
+    NotUseful
+}
+
+enum WitnessPreference {
+    ConstructWitness,
+    LeaveOutWitness
+}
+
+impl Usefulness {
+    fn useful(self) -> Option<Vec<Gc<Pat>>> {
+        match self {
+            Useful(pats) => Some(pats),
+            _ => None
+        }
+    }
+}
+
+fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
+    ty::with_path(tcx, id, |mut path| Path {
+        global: false,
+        segments: path.last().map(|elem| PathSegment {
+            identifier: Ident::new(elem.name()),
+            lifetimes: vec!(),
+            types: OwnedSlice::empty()
+        }).move_iter().collect(),
+        span: DUMMY_SP,
+    })
+}
 
 struct MatchCheckCtxt<'a> {
     tcx: &'a ty::ctxt,
@@ -58,38 +92,39 @@ pub fn check_crate(tcx: &ty::ctxt,
 fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
     visit::walk_expr(cx, ex, ());
     match ex.node {
-      ExprMatch(scrut, ref arms) => {
-        // First, check legality of move bindings.
-        for arm in arms.iter() {
-            check_legality_of_move_bindings(cx,
-                                            arm.guard.is_some(),
-                                            arm.pats.as_slice());
-        }
+        ExprMatch(scrut, ref arms) => {
+            // First, check legality of move bindings.
+            for arm in arms.iter() {
+                check_legality_of_move_bindings(cx,
+                                                arm.guard.is_some(),
+                                                arm.pats.as_slice());
+            }
 
-        check_arms(cx, arms.as_slice());
-        /* Check for exhaustiveness */
-         // Check for empty enum, because is_useful only works on inhabited
-         // types.
-       let pat_ty = node_id_to_type(cx.tcx, scrut.id);
-       if (*arms).is_empty() {
-           if !type_is_empty(cx.tcx, pat_ty) {
-               // We know the type is inhabited, so this must be wrong
-               cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
-                            type {} is non-empty",
-                            ty_to_str(cx.tcx, pat_ty)).as_slice());
-           }
-           // If the type *is* empty, it's vacuously exhaustive
-           return;
-       }
-       let m: matrix = arms
-          .iter()
-          .filter(|&arm| is_unguarded(arm))
-          .flat_map(|arm| arm.pats.iter())
-          .map(|pat| vec!(pat.clone()))
-          .collect();
-       check_exhaustive(cx, ex.span, &m);
-     }
-     _ => ()
+            // Second, check for unreachable arms.
+            check_arms(cx, arms.as_slice());
+
+            // Finally, check if the whole match expression is exhaustive.
+            // Check for empty enum, because is_useful only works on inhabited types.
+            let pat_ty = node_id_to_type(cx.tcx, scrut.id);
+            if (*arms).is_empty() {
+               if !type_is_empty(cx.tcx, pat_ty) {
+                   // We know the type is inhabited, so this must be wrong
+                   cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
+                                type {} is non-empty",
+                                ty_to_str(cx.tcx, pat_ty)).as_slice());
+               }
+               // If the type *is* empty, it's vacuously exhaustive
+               return;
+            }
+            let m: Matrix = arms
+                .iter()
+                .filter(|&arm| is_unguarded(arm))
+                .flat_map(|arm| arm.pats.iter())
+                .map(|pat| vec!(pat.clone()))
+                .collect();
+            check_exhaustive(cx, ex.span, &m);
+        },
+        _ => ()
     }
 }
 
@@ -98,7 +133,6 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
     let mut seen = Vec::new();
     for arm in arms.iter() {
         for pat in arm.pats.iter() {
-
             // Check that we do not match against a static NaN (#6804)
             let pat_matches_nan: |&Pat| -> bool = |p| {
                 let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
@@ -123,11 +157,9 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
             });
 
             let v = vec!(*pat);
-            match is_useful(cx, &seen, v.as_slice()) {
-              not_useful => {
-                cx.tcx.sess.span_err(pat.span, "unreachable pattern");
-              }
-              _ => ()
+            match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
+                NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
+                _ => ()
             }
             if arm.guard.is_none() { seen.push(v); }
         }
@@ -136,80 +168,163 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
 
 fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
     match p.node {
-      PatIdent(_, _, Some(s)) => { raw_pat(s) }
-      _ => { p }
+        PatIdent(_, _, Some(s)) => { raw_pat(s) }
+        _ => { p }
     }
 }
 
-fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &matrix) {
-    let ext = match is_useful(cx, m, [wild()]) {
-        not_useful => {
+fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
+    match is_useful(cx, m, [wild()], ConstructWitness) {
+        NotUseful => {
             // This is good, wildcard pattern isn't reachable
             return;
         }
-        useful_ => None,
-        useful(ty, ref ctor) => {
+        Useful(pats) => {
+            let witness = match pats.as_slice() {
+                [witness] => witness,
+                [] => wild(),
+                _ => unreachable!()
+            };
+            let msg = format!("non-exhaustive patterns: `{0}` not covered", pat_to_str(&*witness));
+            cx.tcx.sess.span_err(sp, msg.as_slice());
+        }
+    }
+}
+
+#[deriving(Clone, PartialEq)]
+enum ctor {
+    single,
+    variant(DefId /* variant */, bool /* is_structure */),
+    val(const_val),
+    range(const_val, const_val),
+    vec(uint)
+}
+
+fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
+    let node = match value {
+        &const_bool(b) => LitBool(b),
+        _ => unreachable!()
+    };
+    box(GC) Expr {
+        id: 0,
+        node: ExprLit(box(GC) Spanned { node: node, span: DUMMY_SP }),
+        span: DUMMY_SP
+    }
+}
+
+fn construct_witness(cx: &MatchCheckCtxt, ctor: &ctor, pats: Vec<Gc<Pat>>, lty: ty::t) -> Gc<Pat> {
+    let pat = match ty::get(lty).sty {
+        ty::ty_tup(_) => PatTup(pats),
+
+        ty::ty_enum(cid, _) | ty::ty_struct(cid, _)  => {
+            let (vid, is_structure) = match ctor {
+                &variant(vid, is_structure) => (vid, is_structure),
+                _ => (cid, true)
+            };
+            if is_structure {
+                let fields = ty::lookup_struct_fields(cx.tcx, vid);
+                let field_pats = fields.move_iter()
+                    .zip(pats.iter())
+                    .map(|(field, pat)| FieldPat {
+                        ident: Ident::new(field.name),
+                        pat: pat.clone()
+                    }).collect();
+                PatStruct(def_to_path(cx.tcx, vid), field_pats, false)
+            } else {
+                PatEnum(def_to_path(cx.tcx, vid), Some(pats))
+            }
+        },
+
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => {
             match ty::get(ty).sty {
-                ty::ty_bool => {
-                    match *ctor {
-                        val(const_bool(true)) => Some("true".to_string()),
-                        val(const_bool(false)) => Some("false".to_string()),
-                        _ => None
-                    }
-                }
-                ty::ty_enum(id, _) => {
-                    let vid = match *ctor {
-                        variant(id) => id,
-                        _ => fail!("check_exhaustive: non-variant ctor"),
-                    };
-                    let variants = ty::enum_variants(cx.tcx, id);
-
-                    match variants.iter().find(|v| v.id == vid) {
-                        Some(v) => {
-                            Some(token::get_ident(v.name).get()
-                                                         .to_str()
-                                                         .into_string())
-                        }
-                        None => {
-                            fail!("check_exhaustive: bad variant in ctor")
-                        }
-                    }
-                }
-                ty::ty_vec(..) | ty::ty_rptr(..) => {
-                    match *ctor {
-                        vec(n) => {
-                            Some(format!("vectors of length {}", n))
-                        }
-                        _ => None
-                    }
+                ty::ty_vec(_, None) => match ctor {
+                    &vec(_) => PatVec(pats, None, vec!()),
+                    _ => unreachable!()
+                },
+                ty::ty_str => PatWild,
+                _ => {
+                    assert_eq!(pats.len(), 1);
+                    PatRegion(pats.get(0).clone())
                 }
-                _ => None
+            }
+        },
+
+        ty::ty_box(_) => {
+            assert_eq!(pats.len(), 1);
+            PatBox(pats.get(0).clone())
+        },
+
+        _ => {
+            match ctor {
+                &vec(_) => PatVec(pats, None, vec!()),
+                &val(ref v) => PatLit(const_val_to_expr(v)),
+                _ => PatWild
             }
         }
     };
-    let msg = format!("non-exhaustive patterns{}", match ext {
-        Some(ref s) => format!(": {} not covered", *s),
-        None => "".to_string()
-    });
-    cx.tcx.sess.span_err(sp, msg.as_slice());
+
+    box(GC) Pat {
+        id: 0,
+        node: pat,
+        span: DUMMY_SP
+    }
 }
 
-type matrix = Vec<Vec<Gc<Pat>>>;
+fn missing_constructor(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Option<ctor> {
+    let used_constructors: Vec<ctor> = m.iter()
+        .filter_map(|r| pat_ctor_id(cx, left_ty, *r.get(0)))
+        .collect();
 
-#[deriving(Clone)]
-enum useful {
-    useful(ty::t, ctor),
-    useful_,
-    not_useful,
+    all_constructors(cx, m, left_ty)
+        .move_iter()
+        .find(|c| !used_constructors.contains(c))
 }
 
-#[deriving(Clone, PartialEq)]
-enum ctor {
-    single,
-    variant(DefId),
-    val(const_val),
-    range(const_val, const_val),
-    vec(uint)
+fn all_constructors(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Vec<ctor> {
+    fn vec_constructors(m: &Matrix) -> Vec<ctor> {
+        let max_vec_len = m.iter().map(|r| match r.get(0).node {
+            PatVec(ref before, _, ref after) => before.len() + after.len(),
+            _ => 0u
+        }).max().unwrap_or(0u);
+        let contains_slice = m.iter().any(|r| match r.get(0).node {
+            PatVec(_, ref slice, _) => slice.is_some(),
+            _ => false
+        });
+        let lengths = iter::range_inclusive(0u, if contains_slice {
+            max_vec_len
+        } else {
+            max_vec_len + 1
+        });
+        lengths.map(|len| vec(len)).collect()
+    }
+
+    match ty::get(left_ty).sty {
+        ty::ty_bool =>
+            [true, false].iter().map(|b| val(const_bool(*b))).collect(),
+
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+            ty::ty_vec(_, None) => vec_constructors(m),
+            _ => vec!(single)
+        },
+
+        ty::ty_enum(eid, _) =>
+            ty::enum_variants(cx.tcx, eid)
+                .iter()
+                .map(|va| variant(va.id, va.arg_names.is_some()))
+                .collect(),
+
+        ty::ty_vec(_, None) =>
+            vec_constructors(m),
+
+        ty::ty_vec(_, Some(n)) =>
+            vec!(vec(n)),
+
+        ty::ty_nil if !m.iter().all(|r| is_wild(cx, *r.get(0))) =>
+            vec!(),
+
+        _ =>
+            vec!(single)
+    }
 }
 
 // Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
@@ -225,12 +340,13 @@ enum ctor {
 
 // Note: is_useful doesn't work on empty types, as the paper notes.
 // So it assumes that v is non-empty.
-fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[Gc<Pat>]) -> useful {
+fn is_useful(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+             witness: WitnessPreference) -> Usefulness {
     if m.len() == 0u {
-        return useful_;
+        return Useful(vec!());
     }
     if m.get(0).len() == 0u {
-        return not_useful
+        return NotUseful;
     }
     let real_pat = match m.iter().find(|r| r.get(0).id != 0) {
         Some(r) => {
@@ -241,310 +357,156 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[Gc<Pat>]) -> useful {
                 _ => *r.get(0)
             }
         }
-        None if v.len() == 0 => return not_useful,
+        None if v.len() == 0 => return NotUseful,
         None => v[0]
     };
-    let left_ty = if real_pat.id == 0 { ty::mk_nil() }
-                  else { ty::node_id_to_type(cx.tcx, real_pat.id) };
-
-    match pat_ctor_id(cx, v[0]) {
-      None => {
-        match missing_ctor(cx, m, left_ty) {
-          None => {
-            match ty::get(left_ty).sty {
-              ty::ty_bool => {
-                  match is_useful_specialized(cx, m, v,
-                                              val(const_bool(true)),
-                                              0u, left_ty){
-                      not_useful => {
-                          is_useful_specialized(cx, m, v,
-                                                val(const_bool(false)),
-                                                0u, left_ty)
-                      }
-                      u => u,
-                  }
-              }
-              ty::ty_enum(eid, _) => {
-                  for va in (*ty::enum_variants(cx.tcx, eid)).iter() {
-                      match is_useful_specialized(cx, m, v, variant(va.id),
-                                                  va.args.len(), left_ty) {
-                        not_useful => (),
-                        u => return u,
-                      }
-                  }
-                  not_useful
-              }
-              ty::ty_vec(_, Some(n)) => {
-                  is_useful_specialized(cx, m, v, vec(n), n, left_ty)
-              }
-              ty::ty_vec(..) => fail!("impossible case"),
-              ty::ty_rptr(_, ty::mt{ty: ty, ..}) | ty::ty_uniq(ty) => match ty::get(ty).sty {
-                  ty::ty_vec(_, None) => {
-                      let max_len = m.iter().rev().fold(0, |max_len, r| {
-                          match r.get(0).node {
-                              PatVec(ref before, _, ref after) => {
-                                  cmp::max(before.len() + after.len(), max_len)
-                              }
-                              _ => max_len
-                          }
-                      });
-                      for n in iter::range(0u, max_len + 1) {
-                          match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
-                              not_useful => (),
-                              u => return u,
-                          }
-                      }
-                      not_useful
-                  }
-                  _ => {
-                      let arity = ctor_arity(cx, &single, left_ty);
-                      is_useful_specialized(cx, m, v, single, arity, left_ty)
-                  }
-              },
-              _ => {
-                  let arity = ctor_arity(cx, &single, left_ty);
-                  is_useful_specialized(cx, m, v, single, arity, left_ty)
-              }
-            }
-          }
-          Some(ctor) => {
-            match is_useful(cx,
-                            &m.iter().filter_map(|r| {
-                                default(cx, r.as_slice())
-                            }).collect::<matrix>(),
-                            v.tail()) {
-              useful_ => useful(left_ty, ctor),
-              u => u,
+    let left_ty = if real_pat.id == 0 {
+        ty::mk_nil()
+    } else {
+        ty::pat_ty(cx.tcx, &*real_pat)
+    };
+
+    match pat_ctor_id(cx, left_ty, v[0]) {
+        None => match missing_constructor(cx, m, left_ty) {
+            None => {
+                all_constructors(cx, m, left_ty).move_iter().filter_map(|c| {
+                    is_useful_specialized(cx, m, v, c.clone(),
+                                          left_ty, witness).useful().map(|pats| {
+                        Useful(match witness {
+                            ConstructWitness => {
+                                let arity = constructor_arity(cx, &c, left_ty);
+                                let subpats = {
+                                    let pat_slice = pats.as_slice();
+                                    Vec::from_fn(arity, |i| {
+                                        pat_slice.get(i).map(|p| p.clone())
+                                            .unwrap_or_else(|| wild())
+                                    })
+                                };
+                                let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
+                                result.extend(pats.move_iter().skip(arity));
+                                result
+                            }
+                            LeaveOutWitness => vec!()
+                        })
+                    })
+                }).nth(0).unwrap_or(NotUseful)
+            },
+
+            Some(ctor) => {
+                let matrix = m.iter().filter_map(|r| default(cx, r.as_slice())).collect();
+                match is_useful(cx, &matrix, v.tail(), witness) {
+                    Useful(pats) => Useful(match witness {
+                        ConstructWitness => {
+                            let arity = constructor_arity(cx, &ctor, left_ty);
+                            let wild_pats = Vec::from_elem(arity, wild());
+                            let enum_pat = construct_witness(cx, &ctor, wild_pats, left_ty);
+                            (vec!(enum_pat)).append(pats.as_slice())
+                        }
+                        LeaveOutWitness => vec!()
+                    }),
+                    result => result
+                }
             }
-          }
-        }
-      }
-      Some(v0_ctor) => {
-        let arity = ctor_arity(cx, &v0_ctor, left_ty);
-        is_useful_specialized(cx, m, v, v0_ctor, arity, left_ty)
-      }
+        },
+
+        Some(v0_ctor) => is_useful_specialized(cx, m, v, v0_ctor, left_ty, witness)
     }
 }
 
-fn is_useful_specialized(cx: &MatchCheckCtxt,
-                             m: &matrix,
-                             v: &[Gc<Pat>],
-                             ctor: ctor,
-                             arity: uint,
-                             lty: ty::t)
-                             -> useful {
-    let ms = m.iter().filter_map(|r| {
-        specialize(cx, r.as_slice(), &ctor, arity, lty)
-    }).collect::<matrix>();
-    let could_be_useful = match specialize(cx, v, &ctor, arity, lty) {
-        Some(v) => is_useful(cx, &ms, v.as_slice()),
-        None => return not_useful,
-    };
-    match could_be_useful {
-      useful_ => useful(lty, ctor),
-      u => u,
+fn is_useful_specialized(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+                         ctor: ctor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
+    let arity = constructor_arity(cx, &ctor, lty);
+    let matrix = m.iter().filter_map(|r| {
+        specialize(cx, r.as_slice(), &ctor, arity)
+    }).collect();
+    match specialize(cx, v, &ctor, arity) {
+        Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
+        None => NotUseful
     }
 }
 
-fn pat_ctor_id(cx: &MatchCheckCtxt, p: Gc<Pat>) -> Option<ctor> {
+fn pat_ctor_id(cx: &MatchCheckCtxt, left_ty: ty::t, p: Gc<Pat>) -> Option<ctor> {
     let pat = raw_pat(p);
     match pat.node {
-      PatWild | PatWildMulti => { None }
-      PatIdent(_, _, _) | PatEnum(_, _) => {
-        let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
-        match opt_def {
-          Some(DefVariant(_, id, _)) => Some(variant(id)),
-          Some(DefStatic(did, false)) => {
-            let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-            Some(val(eval_const_expr(cx.tcx, &*const_expr)))
-          }
-          _ => None
-        }
-      }
-      PatLit(ref expr) => { Some(val(eval_const_expr(cx.tcx, &**expr))) }
-      PatRange(ref lo, ref hi) => {
-        Some(range(eval_const_expr(cx.tcx, &**lo), eval_const_expr(cx.tcx, &**hi)))
-      }
-      PatStruct(..) => {
-        match cx.tcx.def_map.borrow().find(&pat.id) {
-          Some(&DefVariant(_, id, _)) => Some(variant(id)),
-          _ => Some(single)
-        }
-      }
-      PatBox(_) | PatTup(_) | PatRegion(..) => {
-        Some(single)
-      }
-      PatVec(ref before, slice, ref after) => {
-        match slice {
-          Some(_) => None,
-          None => Some(vec(before.len() + after.len()))
-        }
-      }
-      PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
+        PatIdent(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefStatic(did, false)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+                },
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => None
+            },
+        PatEnum(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefStatic(did, false)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+                },
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => Some(single)
+            },
+        PatStruct(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => Some(single)
+            },
+        PatLit(expr) =>
+            Some(val(eval_const_expr(cx.tcx, &*expr))),
+        PatRange(lo, hi) =>
+            Some(range(eval_const_expr(cx.tcx, &*lo), eval_const_expr(cx.tcx, &*hi))),
+        PatVec(ref before, _, ref after) => match ty::get(left_ty).sty {
+            ty::ty_vec(_, Some(n)) =>
+                Some(vec(n)),
+            _ =>
+                Some(vec(before.len() + after.len()))
+        },
+        PatBox(_) | PatTup(_) | PatRegion(..) =>
+            Some(single),
+        PatWild | PatWildMulti =>
+            None,
+        PatMac(_) =>
+            cx.tcx.sess.bug("unexpanded macro")
     }
 }
 
 fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
     let pat = raw_pat(p);
     match pat.node {
-      PatWild | PatWildMulti => { true }
-      PatIdent(_, _, _) => {
-        match cx.tcx.def_map.borrow().find(&pat.id) {
-          Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => { false }
-          _ => { true }
-        }
-      }
-      _ => { false }
-    }
-}
-
-fn missing_ctor(cx: &MatchCheckCtxt,
-                m: &matrix,
-                left_ty: ty::t)
-                -> Option<ctor> {
-    return match ty::get(left_ty).sty {
-      ty::ty_box(_) | ty::ty_tup(_) |
-      ty::ty_struct(..) => check_matrix_for_wild(cx, m),
-      ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
-          ty::ty_vec(_, None) => ctor_for_slice(m),
-          ty::ty_str => Some(single),
-          _ => check_matrix_for_wild(cx, m),
-      },
-      ty::ty_enum(eid, _) => {
-        let pat_ctors: Vec<ctor> = m
-          .iter()
-          .filter_map(|r| pat_ctor_id(cx, *r.get(0)))
-          .collect();
-        let variants = ty::enum_variants(cx.tcx, eid);
-        variants.iter().map(|v| variant(v.id)).find(|c| !pat_ctors.contains(c))
-      }
-      ty::ty_nil => None,
-      ty::ty_bool => {
-        let mut true_found = false;
-        let mut false_found = false;
-        for r in m.iter() {
-            match pat_ctor_id(cx, *r.get(0)) {
-              None => (),
-              Some(val(const_bool(true))) => true_found = true,
-              Some(val(const_bool(false))) => false_found = true,
-              _ => fail!("impossible case")
+        PatWild | PatWildMulti => true,
+        PatIdent(_, _, _) => {
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
+                _ => true
             }
         }
-        if true_found && false_found { None }
-        else if true_found { Some(val(const_bool(false))) }
-        else { Some(val(const_bool(true))) }
-      }
-      ty::ty_vec(_, Some(n)) => {
-        let mut missing = true;
-        let mut wrong = false;
-        for r in m.iter() {
-          match r.get(0).node {
-            PatVec(ref before, ref slice, ref after) => {
-              let count = before.len() + after.len();
-              if (count < n && slice.is_none()) || count > n {
-                wrong = true;
-              }
-              if count == n || (count < n && slice.is_some()) {
-                missing = false;
-              }
-            }
-            _ => {}
-          }
-        }
-        match (wrong, missing) {
-          (true, _) => Some(vec(n)), // should be compile-time error
-          (_, true) => Some(vec(n)),
-          _         => None
-        }
-      }
-      ty::ty_vec(..) => fail!("impossible case"),
-      _ => Some(single)
-    };
-
-    fn check_matrix_for_wild(cx: &MatchCheckCtxt, m: &matrix) -> Option<ctor> {
-        for r in m.iter() {
-            if !is_wild(cx, *r.get(0)) { return None; }
-        }
-        return Some(single);
-    }
-
-    // For slice and ~[T].
-    fn ctor_for_slice(m: &matrix) -> Option<ctor> {
-        // Find the lengths and slices of all vector patterns.
-        let mut vec_pat_lens = m.iter().filter_map(|r| {
-            match r.get(0).node {
-                PatVec(ref before, ref slice, ref after) => {
-                    Some((before.len() + after.len(), slice.is_some()))
-                }
-                _ => None
-            }
-        }).collect::<Vec<(uint, bool)> >();
-
-        // Sort them by length such that for patterns of the same length,
-        // those with a destructured slice come first.
-        vec_pat_lens.sort_by(|&(len1, slice1), &(len2, slice2)| {
-                    if len1 == len2 {
-                        slice2.cmp(&slice1)
-                    } else {
-                        len1.cmp(&len2)
-                    }
-                });
-        vec_pat_lens.dedup();
-
-        let mut found_slice = false;
-        let mut next = 0;
-        let mut missing = None;
-        for &(length, slice) in vec_pat_lens.iter() {
-            if length != next {
-                missing = Some(next);
-                break;
-            }
-            if slice {
-                found_slice = true;
-                break;
-            }
-            next += 1;
-        }
-
-        // We found patterns of all lengths within <0, next), yet there was no
-        // pattern with a slice - therefore, we report vec(next) as missing.
-        if !found_slice {
-            missing = Some(next);
-        }
-        match missing {
-          Some(k) => Some(vec(k)),
-          None => None
-        }
+        _ => false
     }
 }
 
-fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
-    fn vec_ctor_arity(ctor: &ctor) -> uint {
-        match *ctor {
-            vec(n) => n,
-            _ => 0u
-        }
-    }
-
+fn constructor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
     match ty::get(ty).sty {
         ty::ty_tup(ref fs) => fs.len(),
-        ty::ty_box(_) => 1u,
-        ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
-            ty::ty_vec(_, None) => vec_ctor_arity(ctor),
-            _ => 1u,
+        ty::ty_box(_) | ty::ty_uniq(_) => 1u,
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+            ty::ty_vec(_, None) => match *ctor {
+                vec(n) => n,
+                _ => 0u
+            },
+            ty::ty_str => 0u,
+            _ => 1u
         },
         ty::ty_enum(eid, _) => {
-            let id = match *ctor {
-                variant(id) => id,
-                _ => fail!("impossible case")
-            };
-            match ty::enum_variants(cx.tcx, eid).iter().find(|v| v.id == id ) {
-                Some(v) => v.args.len(),
-                None => fail!("impossible case")
+            match *ctor {
+                variant(id, _) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
+                _ => unreachable!()
             }
         }
         ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
-        ty::ty_vec(_, Some(_)) => vec_ctor_arity(ctor),
+        ty::ty_vec(_, _) => match *ctor {
+            vec(n) => n,
+            _ => 0u
+        },
         _ => 0u
     }
 }
@@ -553,10 +515,6 @@ fn wild() -> Gc<Pat> {
     box(GC) Pat {id: 0, node: PatWild, span: DUMMY_SP}
 }
 
-fn wild_multi() -> Gc<Pat> {
-    box(GC) Pat {id: 0, node: PatWildMulti, span: DUMMY_SP}
-}
-
 fn range_covered_by_constructor(ctor_id: &ctor, from: &const_val, to: &const_val) -> Option<bool> {
     let (c_from, c_to) = match *ctor_id {
         val(ref value)          => (value, value),
@@ -572,164 +530,150 @@ fn range_covered_by_constructor(ctor_id: &ctor, from: &const_val, to: &const_val
     }
 }
 
-fn specialize(cx: &MatchCheckCtxt,
-                  r: &[Gc<Pat>],
-                  ctor_id: &ctor,
-                  arity: uint,
-                  left_ty: ty::t)
-               -> Option<Vec<Gc<Pat>>> {
-    let &Pat{id: ref pat_id, node: ref n, span: ref pat_span} = &(*raw_pat(r[0]));
+fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
+              ctor_id: &ctor, arity: uint) -> Option<Vec<Gc<Pat>>> {
+    let &Pat {
+        id: ref pat_id, node: ref n, span: ref pat_span
+    } = &(*raw_pat(r[0]));
     let head: Option<Vec<Gc<Pat>>> = match n {
-            &PatWild => {
-                Some(Vec::from_elem(arity, wild()))
-            }
-            &PatWildMulti => {
-                Some(Vec::from_elem(arity, wild_multi()))
-            }
-            &PatIdent(_, _, _) => {
-                let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
-                match opt_def {
-                    Some(DefVariant(_, id, _)) => {
-                        if variant(id) == *ctor_id {
-                            Some(vec!())
-                        } else {
+        &PatWild => {
+            Some(Vec::from_elem(arity, wild()))
+        }
+        &PatWildMulti => {
+            Some(Vec::from_elem(arity, wild()))
+        }
+        &PatIdent(_, _, _) => {
+            let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
+            match opt_def {
+                Some(DefVariant(_, id, _)) => match *ctor_id {
+                    variant(vid, _) if vid == id => Some(vec!()),
+                    _ => None
+                },
+                Some(DefStatic(did, _)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    let e_v = eval_const_expr(cx.tcx, &*const_expr);
+                    match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+                        Some(true) => Some(vec!()),
+                        Some(false) => None,
+                        None => {
+                            cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                             None
                         }
                     }
-                    Some(DefStatic(did, _)) => {
-                        let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-                        let e_v = eval_const_expr(cx.tcx, &*const_expr);
-                        match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
-                           Some(true) => Some(vec!()),
-                           Some(false) => None,
-                           None => {
-                              cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
-                              None
-                           }
-                        }
-                    }
-                    _ => {
-                        Some(Vec::from_elem(arity, wild()))
-                    }
+                }
+                _ => {
+                    Some(Vec::from_elem(arity, wild()))
                 }
             }
-            &PatEnum(_, ref args) => {
-                let def = cx.tcx.def_map.borrow().get_copy(pat_id);
-                match def {
-                    DefStatic(did, _) => {
-                        let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-                        let e_v = eval_const_expr(cx.tcx, &*const_expr);
-                        match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
-                           Some(true) => Some(vec!()),
-                           Some(false) => None,
-                           None => {
-                              cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
-                              None
-                           }
+        }
+        &PatEnum(_, ref args) => {
+            let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+            match def {
+                DefStatic(did, _) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    let e_v = eval_const_expr(cx.tcx, &*const_expr);
+                    match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+                        Some(true) => Some(vec!()),
+                        Some(false) => None,
+                        None => {
+                            cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
+                            None
                         }
                     }
-                    DefVariant(_, id, _) if variant(id) != *ctor_id => None,
-                    DefVariant(..) | DefFn(..) | DefStruct(..) => {
-                        Some(match args {
-                            &Some(ref args) => args.clone(),
-                            &None => Vec::from_elem(arity, wild())
-                        })
-                    }
-                    _ => None
                 }
+                DefVariant(_, id, _) if variant(id, false) != *ctor_id => None,
+                DefVariant(..) | DefFn(..) | DefStruct(..) => {
+                    Some(match args {
+                        &Some(ref args) => args.clone(),
+                        &None => Vec::from_elem(arity, wild())
+                    })
+                }
+                _ => None
             }
-            &PatStruct(_, ref pattern_fields, _) => {
-                // Is this a struct or an enum variant?
-                let def = cx.tcx.def_map.borrow().get_copy(pat_id);
-                let class_id = match def {
-                    DefVariant(_, variant_id, _) => {
-                      if variant(variant_id) == *ctor_id {
-                        Some(variant_id)
-                      } else {
-                        None
-                      }
-                    }
-                    _ => {
-                        match ty::get(left_ty).sty {
-                            ty::ty_struct(cid, _) => Some(cid),
-                            _ => {
-                                cx.tcx.sess.span_bug(
-                                    *pat_span,
-                                    format!("struct pattern resolved to {}, \
-                                          not a struct",
-                                         ty_to_str(cx.tcx,
-                                                   left_ty)).as_slice());
-                            }
-                        }
+        }
+
+        &PatStruct(_, ref pattern_fields, _) => {
+            // Is this a struct or an enum variant?
+            let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+            let class_id = match def {
+                DefVariant(_, variant_id, _) => if *ctor_id == variant(variant_id, true) {
+                    Some(variant_id)
+                } else {
+                    None
+                },
+                DefStruct(struct_id) => Some(struct_id),
+                _ => None
+            };
+            class_id.map(|variant_id| {
+                let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
+                let args = struct_fields.iter().map(|sf| {
+                    match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
+                        Some(f) => f.pat,
+                        _ => wild()
                     }
-                };
-                class_id.map(|variant_id| {
-                  let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
-                  let args = struct_fields.iter().map(|sf| {
-                      match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
-                          Some(f) => f.pat,
-                          _ => wild()
-                      }
-                  }).collect();
-                  args
-                })
+                }).collect();
+                args
+            })
+        }
 
-            }
-            &PatTup(ref args) => {
-                Some(args.clone())
-            }
-            &PatBox(ref inner) | &PatRegion(ref inner) => {
-                Some(vec!(inner.clone()))
-            }
-            &PatLit(ref expr) => {
-              let expr_value = eval_const_expr(cx.tcx, &**expr);
-              match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
-                 Some(true) => Some(vec!()),
-                 Some(false) => None,
-                 None => {
+        &PatTup(ref args) =>
+            Some(args.clone()),
+
+        &PatBox(ref inner) | &PatRegion(ref inner) =>
+            Some(vec!(inner.clone())),
+
+        &PatLit(ref expr) => {
+            let expr_value = eval_const_expr(cx.tcx, &**expr);
+            match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
+                Some(true) => Some(vec!()),
+                Some(false) => None,
+                None => {
                     cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                     None
-                 }
-              }
+                }
             }
-            &PatRange(ref from, ref to) => {
-              let from_value = eval_const_expr(cx.tcx, &**from);
-              let to_value = eval_const_expr(cx.tcx, &**to);
-              match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
-                 Some(true) => Some(vec!()),
-                 Some(false) => None,
-                 None => {
+        }
+
+        &PatRange(ref from, ref to) => {
+            let from_value = eval_const_expr(cx.tcx, &**from);
+            let to_value = eval_const_expr(cx.tcx, &**to);
+            match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
+                Some(true) => Some(vec!()),
+                Some(false) => None,
+                None => {
                     cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                     None
-                 }
-              }
+                }
             }
-            &PatVec(ref before, ref slice, ref after) => {
-                match *ctor_id {
-                    vec(_) => {
-                        let num_elements = before.len() + after.len();
-                        if num_elements < arity && slice.is_some() {
-                            let mut result = Vec::new();
-                            result.push_all(before.as_slice());
-                            result.grow_fn(arity - num_elements, |_| wild());
-                            result.push_all(after.as_slice());
-                            Some(result)
-                        } else if num_elements == arity {
-                            let mut result = Vec::new();
-                            result.push_all(before.as_slice());
-                            result.push_all(after.as_slice());
-                            Some(result)
-                        } else {
-                            None
-                        }
+        }
+
+        &PatVec(ref before, ref slice, ref after) => {
+            match *ctor_id {
+                vec(_) => {
+                    let num_elements = before.len() + after.len();
+                    if num_elements < arity && slice.is_some() {
+                        let mut result = Vec::new();
+                        result.push_all(before.as_slice());
+                        result.grow_fn(arity - num_elements, |_| wild());
+                        result.push_all(after.as_slice());
+                        Some(result)
+                    } else if num_elements == arity {
+                        let mut result = Vec::new();
+                        result.push_all(before.as_slice());
+                        result.push_all(after.as_slice());
+                        Some(result)
+                    } else {
+                        None
                     }
-                    _ => None
                 }
+                _ => None
             }
-            &PatMac(_) => {
-                cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
-                None
-            }
+        }
+
+        &PatMac(_) => {
+            cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
+            None
+        }
     };
     head.map(|head| head.append(r.tail()))
 }
@@ -750,12 +694,15 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
         LocalFor => "`for` loop"
     };
 
-    let mut spans = vec![];
-    find_refutable(cx, &*loc.pat, &mut spans);
-
-    for span in spans.iter() {
-        cx.tcx.sess.span_err(*span,
-                             format!("refutable pattern in {} binding", name).as_slice());
+    match is_refutable(cx, loc.pat) {
+        Some(pat) => {
+            let msg = format!(
+                "refutable pattern in {} binding: `{}` not covered",
+                name, pat_to_str(&*pat)
+            );
+            cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
+        },
+        None => ()
     }
 
     // Check legality of move bindings.
@@ -769,67 +716,27 @@ fn check_fn(cx: &mut MatchCheckCtxt,
             sp: Span) {
     visit::walk_fn(cx, kind, decl, body, sp, ());
     for input in decl.inputs.iter() {
-        let mut spans = vec![];
-        find_refutable(cx, &*input.pat, &mut spans);
-
-        for span in spans.iter() {
-            cx.tcx.sess.span_err(*span,
-                                 "refutable pattern in function argument");
+        match is_refutable(cx, input.pat) {
+            Some(pat) => {
+                let msg = format!(
+                    "refutable pattern in function argument: `{}` not covered",
+                    pat_to_str(&*pat)
+                );
+                cx.tcx.sess.span_err(input.pat.span, msg.as_slice());
+            },
+            None => ()
         }
     }
 }
 
-fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec<Span>) {
-    macro_rules! this_pattern {
-        () => {
-            {
-                spans.push(pat.span);
-                return
-            }
-        }
-    }
-    let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
-    match opt_def {
-      Some(DefVariant(enum_id, _, _)) => {
-        if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
-            this_pattern!()
-        }
-      }
-      Some(DefStatic(..)) => this_pattern!(),
-      _ => ()
-    }
-
-    match pat.node {
-      PatBox(ref sub) | PatRegion(ref sub) | PatIdent(_, _, Some(ref sub)) => {
-        find_refutable(cx, &**sub, spans)
-      }
-      PatWild | PatWildMulti | PatIdent(_, _, None) => {}
-      PatLit(lit) => {
-          match lit.node {
-            ExprLit(lit) => {
-                match lit.node {
-                    LitNil => {}    // `()`
-                    _ => this_pattern!(),
-                }
-            }
-            _ => this_pattern!(),
-          }
-      }
-      PatRange(_, _) => { this_pattern!() }
-      PatStruct(_, ref fields, _) => {
-          for f in fields.iter() {
-              find_refutable(cx, &*f.pat, spans);
-          }
-      }
-      PatTup(ref elts) | PatEnum(_, Some(ref elts))=> {
-          for elt in elts.iter() {
-              find_refutable(cx, &**elt, spans)
-          }
-      }
-      PatEnum(_,_) => {}
-      PatVec(..) => { this_pattern!() }
-      PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
-    }
+fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
+    let pats = vec!(vec!(pat));
+    is_useful(cx, &pats, [wild()], ConstructWitness)
+        .useful()
+        .map(|pats| {
+            assert_eq!(pats.len(), 1);
+            pats.get(0).clone()
+        })
 }
 
 // Legality of move bindings checking
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index ffd29ffeb8f..5b9c89f6250 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -988,8 +988,7 @@ fn extract_vec_elems<'a>(
                      pat_id: ast::NodeId,
                      elem_count: uint,
                      slice: Option<uint>,
-                     val: ValueRef,
-                     count: ValueRef)
+                     val: ValueRef)
                      -> ExtractedBlock<'a> {
     let _icx = push_ctxt("match::extract_vec_elems");
     let vec_datum = match_datum(bcx, val, pat_id);
@@ -1003,7 +1002,7 @@ fn extract_vec_elems<'a>(
             Some(n) if i < n => GEPi(bcx, base, [i]),
             Some(n) if i > n => {
                 InBoundsGEP(bcx, base, [
-                    Sub(bcx, count,
+                    Sub(bcx, len,
                         C_int(bcx.ccx(), (elem_count - i) as int))])
             }
             _ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty.to_ref()) }
@@ -1765,7 +1764,7 @@ fn compile_submatch_continue<'a, 'b>(
                     vec_len_eq => (n, None)
                 };
                 let args = extract_vec_elems(opt_cx, pat_id, n,
-                                             slice, val, test_val);
+                                             slice, val);
                 size = args.vals.len();
                 unpacked = args.vals.clone();
                 opt_cx = args.bcx;
@@ -2264,9 +2263,21 @@ fn bind_irrefutable_pat<'a>(
             let loaded_val = Load(bcx, val);
             bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode, cleanup_scope);
         }
-        ast::PatVec(..) => {
-            bcx.sess().span_bug(pat.span,
-                                "vector patterns are never irrefutable!");
+        ast::PatVec(ref before, ref slice, ref after) => {
+            let extracted = extract_vec_elems(
+                bcx, pat.id, before.len() + 1u + after.len(),
+                slice.map(|_| before.len()), val
+            );
+            bcx = before
+                .iter().map(|v| Some(*v))
+                .chain(Some(*slice).move_iter())
+                .chain(after.iter().map(|v| Some(*v)))
+                .zip(extracted.vals.iter())
+                .fold(bcx, |bcx, (inner, elem)| {
+                    inner.map_or(bcx, |inner| {
+                        bind_irrefutable_pat(bcx, inner, *elem, binding_mode, cleanup_scope)
+                    })
+                });
         }
         ast::PatMac(..) => {
             bcx.sess().span_bug(pat.span, "unexpanded macro");
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index edb77e04b30..e198653165a 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -632,9 +632,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
             fcx.infcx().next_region_var(
                 infer::PatternRegion(pat.span));
 
-        let check_err = || {
-            for elt in before.iter() {
-                check_pat(pcx, &**elt, ty::mk_err());
+        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());
@@ -653,15 +653,16 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
                     })
                 },
                 Some(expected),
-                "a vector pattern".to_string(),
+                found,
                 None);
             fcx.write_error(pat.id);
         };
 
-        let (elt_type, region_var, mutbl) = match *structure_of(fcx,
+        let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
                                                                 pat.span,
                                                                 expected) {
-          ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable),
+          ty::ty_vec(mt, Some(fixed)) =>
+            (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
           ty::ty_uniq(t) => match ty::get(t).sty {
               ty::ty_vec(mt, None) => {
                   fcx.type_error_message(pat.span,
@@ -671,25 +672,37 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
                                          },
                                          expected,
                                          None);
-                  (mt.ty, default_region_var, ast::MutImmutable)
+                  (mt.ty, default_region_var, ast::MutImmutable, None)
               }
               _ => {
-                  check_err();
+                  check_err("a vector pattern".to_string());
                   return;
               }
           },
           ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
-              ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl),
+              ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
               _ => {
-                  check_err();
+                  check_err("a vector pattern".to_string());
                   return;
               }
           },
           _ => {
-              check_err();
+              check_err("a vector 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 vector pattern of size at least {}", min_len)),
+
+            None if count != min_len =>
+                Some(format!("a fixed vector pattern of size {}", min_len)),
+
+            _ => None
+        }).map(check_err);
+
         for elt in before.iter() {
             check_pat(pcx, &**elt, elt_type);
         }
diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs
new file mode 100644
index 00000000000..2b769b9e499
--- /dev/null
+++ b/src/test/compile-fail/issue-13482.rs
@@ -0,0 +1,18 @@
+// 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.
+
+fn main() {
+  let x = [1,2];
+  let y = match x {
+    [] => None,
+//~^ ERROR expected `[<generic integer #1>, .. 2]` but found a fixed vector pattern of size 0
+    [a,_] => Some(a)
+  };
+}
diff --git a/src/test/compile-fail/issue-2111.rs b/src/test/compile-fail/issue-2111.rs
index 40010b203aa..3d9c7401ded 100644
--- a/src/test/compile-fail/issue-2111.rs
+++ b/src/test/compile-fail/issue-2111.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 fn foo(a: Option<uint>, b: Option<uint>) {
-  match (a,b) { //~ ERROR: non-exhaustive patterns: None not covered
+  match (a,b) {
+  //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
     (Some(a), Some(b)) if a == b => { }
     (Some(_), None) |
     (None, Some(_)) => { }
diff --git a/src/test/compile-fail/issue-4321.rs b/src/test/compile-fail/issue-4321.rs
new file mode 100644
index 00000000000..d589680b0ec
--- /dev/null
+++ b/src/test/compile-fail/issue-4321.rs
@@ -0,0 +1,18 @@
+// 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.
+
+fn main() {
+    let tup = (true, true);
+    println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
+        (false, false) => "foo",
+        (false, true) => "bar",
+        (true, true) => "baz"
+    });
+}
diff --git a/src/test/compile-fail/non-exhaustive-match-nested.rs b/src/test/compile-fail/non-exhaustive-match-nested.rs
index 102772f79d5..483168bb8bc 100644
--- a/src/test/compile-fail/non-exhaustive-match-nested.rs
+++ b/src/test/compile-fail/non-exhaustive-match-nested.rs
@@ -8,13 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: non-exhaustive patterns
 enum t { a(u), b }
 enum u { c, d }
 
 fn main() {
   let x = a(c);
-  match x {
+  match x { //~ ERROR non-exhaustive patterns: `a(c)` not covered
       a(d) => { fail!("hello"); }
       b => { fail!("goodbye"); }
     }
diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs
index a07fec853fc..cd78419439a 100644
--- a/src/test/compile-fail/non-exhaustive-match.rs
+++ b/src/test/compile-fail/non-exhaustive-match.rs
@@ -12,21 +12,21 @@ enum t { a, b, }
 
 fn main() {
     let x = a;
-    match x { b => { } } //~ ERROR non-exhaustive patterns
-    match true { //~ ERROR non-exhaustive patterns
+    match x { b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
+    match true { //~ ERROR non-exhaustive patterns: `false` not covered
       true => {}
     }
-    match Some(10) { //~ ERROR non-exhaustive patterns
+    match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
       None => {}
     }
-    match (2, 3, 4) { //~ ERROR non-exhaustive patterns
+    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
       (_, _, 4) => {}
     }
-    match (a, a) { //~ ERROR non-exhaustive patterns
+    match (a, a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
       (a, b) => {}
       (b, a) => {}
     }
-    match a { //~ ERROR b not covered
+    match a { //~ ERROR non-exhaustive patterns: `b` not covered
       a => {}
     }
     // This is exhaustive, though the algorithm got it wrong at one point
@@ -37,8 +37,7 @@ fn main() {
     }
     let vec = vec!(Some(42), None, Some(21));
     let vec: &[Option<int>] = vec.as_slice();
-    match vec {
-        //~^ ERROR non-exhaustive patterns: vectors of length 0 not covered
+    match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
         [Some(..), None, ..tail] => {}
         [Some(..), Some(..), ..tail] => {}
         [None] => {}
@@ -51,7 +50,7 @@ fn main() {
     }
     let vec = vec!(0.5);
     let vec: &[f32] = vec.as_slice();
-    match vec { //~ ERROR non-exhaustive patterns: vectors of length 4 not covered
+    match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
         [0.1, 0.2, 0.3] => (),
         [0.1, 0.2] => (),
         [0.1] => (),
diff --git a/src/test/compile-fail/non-exhaustive-pattern-witness.rs b/src/test/compile-fail/non-exhaustive-pattern-witness.rs
new file mode 100644
index 00000000000..22e93d70858
--- /dev/null
+++ b/src/test/compile-fail/non-exhaustive-pattern-witness.rs
@@ -0,0 +1,74 @@
+// 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.
+
+#![feature(struct_variant)]
+
+struct Foo {
+    first: bool,
+    second: Option<[uint, ..4]>
+}
+
+enum Color {
+    Red,
+    Green,
+    CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+}
+
+fn struct_with_a_nested_enum_and_vector() {
+    match Foo { first: true, second: None } {
+    //~^ ERROR non-exhaustive patterns: `Foo{first: false, second: Some([_, _, _, _])}` not covered
+        Foo { first: true, second: None } => (),
+        Foo { first: true, second: Some(_) } => (),
+        Foo { first: false, second: None } => (),
+        Foo { first: false, second: Some([1u, 2u, 3u, 4u]) } => ()
+    }
+}
+
+fn enum_with_multiple_missing_variants() {
+    match Red {
+    //~^ ERROR non-exhaustive patterns: `Red` not covered
+        CustomRGBA { .. } => ()
+    }
+}
+
+fn enum_struct_variant() {
+    match Red {
+    //~^ ERROR non-exhaustive patterns: `CustomRGBA{a: true, r: _, g: _, b: _}` not covered
+        Red => (),
+        Green => (),
+        CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
+        CustomRGBA { a: false, r: _, g: _, b: _ } => ()
+    }
+}
+
+enum Enum {
+    First,
+    Second(bool)
+}
+
+fn vectors_with_nested_enums() {
+    let x: &'static [Enum] = [First, Second(false)];
+    match x {
+    //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
+        [] => (),
+        [_] => (),
+        [First, _] => (),
+        [Second(true), First] => (),
+        [Second(true), Second(true)] => (),
+        [Second(false), _] => (),
+        [_, _, ..tail, _] => ()
+    }
+}
+
+fn main() {
+    struct_with_a_nested_enum_and_vector();
+    enum_with_multiple_missing_variants();
+    enum_struct_variant();
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/precise-refutable-pattern-errors.rs b/src/test/compile-fail/precise-refutable-pattern-errors.rs
deleted file mode 100644
index efa2dbad83f..00000000000
--- a/src/test/compile-fail/precise-refutable-pattern-errors.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-
-fn func(
-    (
-        1, //~ ERROR refutable pattern in function argument
-        (
-            Some( //~ ERROR refutable pattern in function argument
-                1), // nested, so no warning.
-            2..3 //~ ERROR refutable pattern in function argument
-            )
-        ): (int, (Option<int>, int))
-        ) {}
-
-fn main() {
-    let (
-        1, //~ ERROR refutable pattern in local binding
-        (
-            Some( //~ ERROR refutable pattern in local binding
-                1), // nested, so no warning.
-            2..3 //~ ERROR refutable pattern in local binding
-            )
-        ) = (1, (None, 2));
-}
diff --git a/src/test/compile-fail/refutable-pattern-errors.rs b/src/test/compile-fail/refutable-pattern-errors.rs
new file mode 100644
index 00000000000..9128ee68e26
--- /dev/null
+++ b/src/test/compile-fail/refutable-pattern-errors.rs
@@ -0,0 +1,18 @@
+// 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.
+
+
+fn func((1, (Some(1), 2..3)): (int, (Option<int>, int))) { }
+//~^ ERROR refutable pattern in function argument: `(_, _)` not covered
+
+fn main() {
+    let (1, (Some(1), 2..3)) = (1, (None, 2));
+    //~^ ERROR refutable pattern in local binding: `(_, _)` not covered
+}
diff --git a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs
index d5489b6a852..954d4b23e30 100644
--- a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs
+++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    let f = |3: int| println!("hello");  //~ ERROR refutable pattern
+    let f = |3: int| println!("hello");
+    //~^ ERROR refutable pattern in function argument: `_` not covered
     f(4);
 }
diff --git a/src/test/run-pass/issue-14393.rs b/src/test/run-pass/issue-14393.rs
new file mode 100644
index 00000000000..87108294ff3
--- /dev/null
+++ b/src/test/run-pass/issue-14393.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.
+
+// ignore-win32: FIXME #13793
+
+fn main() {
+    match ("", 1u) {
+        (_, 42u) => (),
+        ("", _) => (),
+        _ => ()
+    }
+}
diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs
new file mode 100644
index 00000000000..52c2d57753a
--- /dev/null
+++ b/src/test/run-pass/issue-7784.rs
@@ -0,0 +1,36 @@
+// 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.
+
+fn foo<T: Add<T, T> + Clone>([x, y, z]: [T, ..3]) -> (T, T, T) {
+    (x.clone(), x.clone() + y.clone(), x + y + z)
+}
+fn bar(a: &'static str, b: &'static str) -> [&'static str, ..4] {
+    [a, b, b, a]
+}
+
+fn main() {
+    assert_eq!(foo([1, 2, 3]), (1, 3, 6));
+
+    let [a, b, c, d] = bar("foo", "bar");
+    assert_eq!(a, "foo");
+    assert_eq!(b, "bar");
+    assert_eq!(c, "bar");
+    assert_eq!(d, "foo");
+
+    let [a, _, _, d] = bar("baz", "foo");
+    assert_eq!(a, "baz");
+    assert_eq!(d, "baz");
+
+    let out = bar("baz", "foo");
+    let [a, ..xs, d] = out;
+    assert_eq!(a, "baz");
+    assert!(xs == ["foo", "foo"]);
+    assert_eq!(d, "baz");
+}
\ No newline at end of file