about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/construct.rs3
-rw-r--r--src/librustc/hir/mod.rs15
-rw-r--r--src/librustc/hir/pat_util.rs75
-rw-r--r--src/librustc/middle/expr_use_visitor.rs157
-rw-r--r--src/librustc/middle/liveness.rs14
-rw-r--r--src/librustc/ty/util.rs4
-rw-r--r--src/librustc_const_eval/check_match.rs46
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs2
-rw-r--r--src/librustc_trans/_match.rs22
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs5
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs8
-rw-r--r--src/librustc_typeck/check/_match.rs22
-rw-r--r--src/librustc_typeck/check/mod.rs20
-rw-r--r--src/librustc_typeck/check/regionck.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs8
-rw-r--r--src/libsyntax/ast.rs18
17 files changed, 168 insertions, 255 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 61c0f1c1c64..76b53094a72 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -456,8 +456,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                     // Visit the guard expression
                     let guard_exit = self.expr(&guard, guard_start);
 
-                    let this_has_bindings = pat_util::pat_contains_bindings_or_wild(
-                        &self.tcx.def_map.borrow(), &pat);
+                    let this_has_bindings = pat_util::pat_contains_bindings_or_wild(&pat);
 
                     // If both this pattern and the previous pattern
                     // were free of bindings, they must consist only
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 0e89dde70ee..bf3d003f51c 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -524,14 +524,7 @@ pub enum PatKind {
     /// Represents a wildcard pattern (`_`)
     Wild,
 
-    /// A `PatKind::Ident` may either be a new bound variable,
-    /// or a unit struct/variant pattern, or a const pattern (in the last two cases
-    /// the third field must be `None`).
-    ///
-    /// In the unit or const pattern case, the parser can't determine
-    /// which it is. The resolver determines this, and
-    /// records this pattern's `NodeId` in an auxiliary
-    /// set (of "PatIdents that refer to unit patterns or constants").
+    /// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
     Binding(BindingMode, Spanned<Name>, Option<P<Pat>>),
 
     /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
@@ -547,10 +540,8 @@ pub enum PatKind {
     /// Such pattern can be resolved to a unit struct/variant or a constant.
     Path(Path),
 
-    /// An associated const named using the qualified path `<T>::CONST` or
-    /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
-    /// referred to as simply `T::CONST`, in which case they will end up as
-    /// PatKind::Path, and the resolver will have to sort that out.
+    /// A path pattern written in qualified form, i.e. `<T as Trait>::CONST` or `<T>::CONST`.
+    /// Such patterns can only refer to associated constants at the moment.
     QPath(QSelf, Path),
 
     /// A tuple pattern `(a, b)`.
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 35a7f7174cb..27530d8c75d 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -10,14 +10,12 @@
 
 use hir::def::*;
 use hir::def_id::DefId;
+use hir::{self, PatKind};
 use ty::TyCtxt;
 use util::nodemap::FnvHashMap;
-
 use syntax::ast;
-use hir::{self, PatKind};
-use syntax::codemap::{respan, Span, Spanned, DUMMY_SP};
+use syntax::codemap::{Span, Spanned, DUMMY_SP};
 
-use std::cell::RefCell;
 use std::iter::{Enumerate, ExactSizeIterator};
 
 pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
@@ -57,9 +55,9 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
 
 // This is used because same-named variables in alternative patterns need to
 // use the NodeId of their namesake in the first pattern.
-pub fn pat_id_map(dm: &RefCell<DefMap>, pat: &hir::Pat) -> PatIdMap {
+pub fn pat_id_map(pat: &hir::Pat) -> PatIdMap {
     let mut map = FnvHashMap();
-    pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
+    pat_bindings(pat, |_bm, p_id, _s, path1| {
         map.insert(path1.node, p_id);
     });
     map
@@ -123,31 +121,14 @@ pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
     }
 }
 
-pub fn pat_is_binding(_: &DefMap, pat: &hir::Pat) -> bool {
-    match pat.node {
-        PatKind::Binding(..) => true,
-        _ => false
-    }
-}
-
-pub fn pat_is_binding_or_wild(_: &DefMap, pat: &hir::Pat) -> bool {
-    match pat.node {
-        PatKind::Binding(..) | PatKind::Wild => true,
-        _ => false
-    }
-}
-
-/// Call `it` on every "binding" in a pattern, e.g., on `a` in
+/// Call `f` on every "binding" in a pattern, e.g., on `a` in
 /// `match foo() { Some(a) => (), None => () }`
-pub fn pat_bindings<I>(_: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
-    I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
+pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)
+    where F: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
 {
     pat.walk(|p| {
-        match p.node {
-          PatKind::Binding(binding_mode, ref pth, _) => {
-            it(binding_mode, p.id, p.span, &respan(pth.span, pth.node));
-          }
-          _ => {}
+        if let PatKind::Binding(binding_mode, ref pth, _) = p.node {
+            f(binding_mode, p.id, p.span, pth);
         }
         true
     });
@@ -155,10 +136,10 @@ pub fn pat_bindings<I>(_: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
 
 /// Checks if the pattern contains any patterns that bind something to
 /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
-pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool {
+pub fn pat_contains_bindings(pat: &hir::Pat) -> bool {
     let mut contains_bindings = false;
     pat.walk(|p| {
-        if pat_is_binding(dm, p) {
+        if let PatKind::Binding(..) = p.node {
             contains_bindings = true;
             false // there's at least one binding, can short circuit now.
         } else {
@@ -170,18 +151,15 @@ pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool {
 
 /// Checks if the pattern contains any `ref` or `ref mut` bindings,
 /// and if yes whether its containing mutable ones or just immutables ones.
-pub fn pat_contains_ref_binding(dm: &RefCell<DefMap>, pat: &hir::Pat) -> Option<hir::Mutability> {
+pub fn pat_contains_ref_binding(pat: &hir::Pat) -> Option<hir::Mutability> {
     let mut result = None;
-    pat_bindings(dm, pat, |mode, _, _, _| {
-        match mode {
-            hir::BindingMode::BindByRef(m) => {
-                // Pick Mutable as maximum
-                match result {
-                    None | Some(hir::MutImmutable) => result = Some(m),
-                    _ => (),
-                }
+    pat_bindings(pat, |mode, _, _, _| {
+        if let hir::BindingMode::BindByRef(m) = mode {
+            // Pick Mutable as maximum
+            match result {
+                None | Some(hir::MutImmutable) => result = Some(m),
+                _ => (),
             }
-            hir::BindingMode::BindByValue(_) => { }
         }
     });
     result
@@ -189,9 +167,9 @@ pub fn pat_contains_ref_binding(dm: &RefCell<DefMap>, pat: &hir::Pat) -> Option<
 
 /// Checks if the patterns for this arm contain any `ref` or `ref mut`
 /// bindings, and if yes whether its containing mutable ones or just immutables ones.
-pub fn arm_contains_ref_binding(dm: &RefCell<DefMap>, arm: &hir::Arm) -> Option<hir::Mutability> {
+pub fn arm_contains_ref_binding(arm: &hir::Arm) -> Option<hir::Mutability> {
     arm.pats.iter()
-            .filter_map(|pat| pat_contains_ref_binding(dm, pat))
+            .filter_map(|pat| pat_contains_ref_binding(pat))
             .max_by_key(|m| match *m {
                 hir::MutMutable => 1,
                 hir::MutImmutable => 0,
@@ -200,14 +178,15 @@ pub fn arm_contains_ref_binding(dm: &RefCell<DefMap>, arm: &hir::Arm) -> Option<
 
 /// Checks if the pattern contains any patterns that bind something to
 /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
-pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
+pub fn pat_contains_bindings_or_wild(pat: &hir::Pat) -> bool {
     let mut contains_bindings = false;
     pat.walk(|p| {
-        if pat_is_binding_or_wild(dm, p) {
-            contains_bindings = true;
-            false // there's at least one binding/wildcard, can short circuit now.
-        } else {
-            true
+        match p.node {
+            PatKind::Binding(..) | PatKind::Wild => {
+                contains_bindings = true;
+                false // there's at least one binding/wildcard, can short circuit now.
+            }
+            _ => true
         }
     });
     contains_bindings
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 12517d927de..cf07493fa7b 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -612,8 +612,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         match local.init {
             None => {
                 let delegate = &mut self.delegate;
-                pat_util::pat_bindings(&self.mc.infcx.tcx.def_map, &local.pat,
-                                       |_, id, span, _| {
+                pat_util::pat_bindings(&local.pat, |_, id, span, _| {
                     delegate.decl_without_init(id, span);
                 })
             }
@@ -932,23 +931,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
                pat);
         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
-            let def_map = &self.tcx().def_map;
-            if pat_util::pat_is_binding(&def_map.borrow(), pat) {
-                match pat.node {
-                    PatKind::Binding(hir::BindByRef(_), _, _) =>
-                        mode.lub(BorrowingMatch),
-                    PatKind::Binding(hir::BindByValue(_), _, _) => {
-                        match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
-                            Copy => mode.lub(CopyingMatch),
-                            Move(_) => mode.lub(MovingMatch),
-                        }
-                    }
-                    _ => {
-                        span_bug!(
-                            pat.span,
-                            "binding pattern not an identifier");
+            match pat.node {
+                PatKind::Binding(hir::BindByRef(..), _, _) =>
+                    mode.lub(BorrowingMatch),
+                PatKind::Binding(hir::BindByValue(..), _, _) => {
+                    match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
+                        Copy => mode.lub(CopyingMatch),
+                        Move(..) => mode.lub(MovingMatch),
                     }
                 }
+                _ => {}
             }
         }));
     }
@@ -968,83 +960,74 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         let def_map = &self.tcx().def_map;
         let delegate = &mut self.delegate;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
-            if pat_util::pat_is_binding(&def_map.borrow(), pat) {
-                debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
-                       cmt_pat,
-                       pat,
-                       match_mode);
-
-                // pat_ty: the type of the binding being produced.
-                let pat_ty = return_if_err!(infcx.node_ty(pat.id));
-
-                // Each match binding is effectively an assignment to the
-                // binding being produced.
-                let def = def_map.borrow().get(&pat.id).unwrap().full_def();
-                match mc.cat_def(pat.id, pat.span, pat_ty, def) {
-                    Ok(binding_cmt) => {
+            match pat.node {
+                PatKind::Binding(bmode, _, _) => {
+                    debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
+                           cmt_pat,
+                           pat,
+                           match_mode);
+
+                    // pat_ty: the type of the binding being produced.
+                    let pat_ty = return_if_err!(infcx.node_ty(pat.id));
+
+                    // Each match binding is effectively an assignment to the
+                    // binding being produced.
+                    let def = def_map.borrow().get(&pat.id).unwrap().full_def();
+                    if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) {
                         delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
                     }
-                    Err(_) => { }
-                }
 
-                // It is also a borrow or copy/move of the value being matched.
-                match pat.node {
-                    PatKind::Binding(hir::BindByRef(m), _, _) => {
-                        if let ty::TyRef(&r, _) = pat_ty.sty {
-                            let bk = ty::BorrowKind::from_mutbl(m);
-                            delegate.borrow(pat.id, pat.span, cmt_pat,
-                                            r, bk, RefBinding);
+                    // It is also a borrow or copy/move of the value being matched.
+                    match bmode {
+                        hir::BindByRef(m) => {
+                            if let ty::TyRef(&r, _) = pat_ty.sty {
+                                let bk = ty::BorrowKind::from_mutbl(m);
+                                delegate.borrow(pat.id, pat.span, cmt_pat,
+                                                r, bk, RefBinding);
+                            }
+                        }
+                        hir::BindByValue(..) => {
+                            let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
+                            debug!("walk_pat binding consuming pat");
+                            delegate.consume_pat(pat, cmt_pat, mode);
                         }
-                    }
-                    PatKind::Binding(hir::BindByValue(_), _, _) => {
-                        let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
-                        debug!("walk_pat binding consuming pat");
-                        delegate.consume_pat(pat, cmt_pat, mode);
-                    }
-                    _ => {
-                        span_bug!(
-                            pat.span,
-                            "binding pattern not an identifier");
                     }
                 }
-            } else {
-                match pat.node {
-                    PatKind::Vec(_, Some(ref slice_pat), _) => {
-                        // The `slice_pat` here creates a slice into
-                        // the original vector.  This is effectively a
-                        // borrow of the elements of the vector being
-                        // matched.
-
-                        let (slice_cmt, slice_mutbl, slice_r) =
-                            return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));
-
-                        // Note: We declare here that the borrow
-                        // occurs upon entering the `[...]`
-                        // pattern. This implies that something like
-                        // `[a; b]` where `a` is a move is illegal,
-                        // because the borrow is already in effect.
-                        // In fact such a move would be safe-ish, but
-                        // it effectively *requires* that we use the
-                        // nulling out semantics to indicate when a
-                        // value has been moved, which we are trying
-                        // to move away from.  Otherwise, how can we
-                        // indicate that the first element in the
-                        // vector has been moved?  Eventually, we
-                        // could perhaps modify this rule to permit
-                        // `[..a, b]` where `b` is a move, because in
-                        // that case we can adjust the length of the
-                        // original vec accordingly, but we'd have to
-                        // make trans do the right thing, and it would
-                        // only work for `Box<[T]>`s. It seems simpler
-                        // to just require that people call
-                        // `vec.pop()` or `vec.unshift()`.
-                        let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
-                        delegate.borrow(pat.id, pat.span,
-                                        slice_cmt, slice_r,
-                                        slice_bk, RefBinding);
-                    }
-                    _ => { }
+                PatKind::Vec(_, Some(ref slice_pat), _) => {
+                    // The `slice_pat` here creates a slice into
+                    // the original vector.  This is effectively a
+                    // borrow of the elements of the vector being
+                    // matched.
+
+                    let (slice_cmt, slice_mutbl, slice_r) =
+                        return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));
+
+                    // Note: We declare here that the borrow
+                    // occurs upon entering the `[...]`
+                    // pattern. This implies that something like
+                    // `[a; b]` where `a` is a move is illegal,
+                    // because the borrow is already in effect.
+                    // In fact such a move would be safe-ish, but
+                    // it effectively *requires* that we use the
+                    // nulling out semantics to indicate when a
+                    // value has been moved, which we are trying
+                    // to move away from.  Otherwise, how can we
+                    // indicate that the first element in the
+                    // vector has been moved?  Eventually, we
+                    // could perhaps modify this rule to permit
+                    // `[..a, b]` where `b` is a move, because in
+                    // that case we can adjust the length of the
+                    // original vec accordingly, but we'd have to
+                    // make trans do the right thing, and it would
+                    // only work for `Box<[T]>`s. It seems simpler
+                    // to just require that people call
+                    // `vec.pop()` or `vec.unshift()`.
+                    let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
+                    delegate.borrow(pat.id, pat.span,
+                                    slice_cmt, slice_r,
+                                    slice_bk, RefBinding);
                 }
+                _ => {}
             }
         }));
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index be8caeb436a..f6ea10a70eb 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -380,9 +380,7 @@ fn visit_fn(ir: &mut IrMaps,
     debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
 
     for arg in &decl.inputs {
-        pat_util::pat_bindings(&ir.tcx.def_map,
-                               &arg.pat,
-                               |_bm, arg_id, _x, path1| {
+        pat_util::pat_bindings(&arg.pat, |_bm, arg_id, _x, path1| {
             debug!("adding argument {}", arg_id);
             let name = path1.node;
             fn_maps.add_variable(Arg(arg_id, name));
@@ -415,7 +413,7 @@ fn visit_fn(ir: &mut IrMaps,
 }
 
 fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
-    pat_util::pat_bindings(&ir.tcx.def_map, &local.pat, |_, p_id, sp, path1| {
+    pat_util::pat_bindings(&local.pat, |_, p_id, sp, path1| {
         debug!("adding local variable {}", p_id);
         let name = path1.node;
         ir.add_live_node_for_node(p_id, VarDefNode(sp));
@@ -429,7 +427,7 @@ fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
 
 fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
     for pat in &arm.pats {
-        pat_util::pat_bindings(&ir.tcx.def_map, &pat, |bm, p_id, sp, path1| {
+        pat_util::pat_bindings(&pat, |bm, p_id, sp, path1| {
             debug!("adding local variable {} from match with bm {:?}",
                    p_id, bm);
             let name = path1.node;
@@ -589,7 +587,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
         F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
     {
-        pat_util::pat_bindings(&self.ir.tcx.def_map, pat, |_bm, p_id, sp, _n| {
+        pat_util::pat_bindings(pat, |_bm, p_id, sp, _n| {
             let ln = self.live_node(p_id, sp);
             let var = self.variable(p_id, sp);
             f(self, ln, var, sp, p_id);
@@ -1567,9 +1565,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
         for arg in &decl.inputs {
-            pat_util::pat_bindings(&self.ir.tcx.def_map,
-                                   &arg.pat,
-                                   |_bm, p_id, sp, path1| {
+            pat_util::pat_bindings(&arg.pat, |_bm, p_id, sp, path1| {
                 let var = self.variable(p_id, sp);
                 // Ignore unused self.
                 let name = path1.node;
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 4f6188ea3c5..a4df0287216 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -173,11 +173,11 @@ impl<'tcx> ParameterEnvironment<'tcx> {
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn pat_contains_ref_binding(self, pat: &hir::Pat) -> Option<hir::Mutability> {
-        pat_util::pat_contains_ref_binding(&self.def_map, pat)
+        pat_util::pat_contains_ref_binding(pat)
     }
 
     pub fn arm_contains_ref_binding(self, arm: &hir::Arm) -> Option<hir::Mutability> {
-        pat_util::arm_contains_ref_binding(&self.def_map, arm)
+        pat_util::arm_contains_ref_binding(arm)
     }
 
     /// Returns the type of element at index `i` in tuple or tuple-like type `t`.
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 46e05d218fc..49fa1896ff8 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -748,10 +748,9 @@ fn is_useful(cx: &MatchCheckCtxt,
             }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
         } else {
             let matrix = rows.iter().filter_map(|r| {
-                if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
-                    Some(r[1..].to_vec())
-                } else {
-                    None
+                match raw_pat(r[0]).node {
+                    PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
+                    _ => None,
                 }
             }).collect();
             match is_useful(cx, &matrix, &v[1..], witness) {
@@ -1089,17 +1088,11 @@ fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A>
 fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
                                    has_guard: bool,
                                    pats: &[P<Pat>]) {
-    let tcx = cx.tcx;
-    let def_map = &tcx.def_map;
     let mut by_ref_span = None;
     for pat in pats {
-        pat_bindings(def_map, &pat, |bm, _, span, _path| {
-            match bm {
-                hir::BindByRef(_) => {
-                    by_ref_span = Some(span);
-                }
-                hir::BindByValue(_) => {
-                }
+        pat_bindings(&pat, |bm, _, span, _path| {
+            if let hir::BindByRef(..) = bm {
+                by_ref_span = Some(span);
             }
         })
     }
@@ -1108,7 +1101,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
         // check legality of moving out of the enum
 
         // x @ Foo(..) is legal, but x @ Foo(y) isn't.
-        if sub.map_or(false, |p| pat_contains_bindings(&def_map.borrow(), &p)) {
+        if sub.map_or(false, |p| pat_contains_bindings(&p)) {
             span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings");
         } else if has_guard {
             span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
@@ -1123,7 +1116,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
     for pat in pats {
         pat.walk(|p| {
             if let PatKind::Binding(hir::BindByValue(..), _, ref sub) = p.node {
-                let pat_ty = tcx.node_id_to_type(p.id);
+                let pat_ty = cx.tcx.node_id_to_type(p.id);
                 //FIXME: (@jroesch) this code should be floated up as well
                 cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()),
                                   ProjectionMode::AnyFinal).enter(|infcx| {
@@ -1199,18 +1192,19 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
     fn visit_pat(&mut self, pat: &Pat) {
-        if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) {
-            span_err!(self.cx.tcx.sess, pat.span, E0303,
-                                      "pattern bindings are not allowed \
-                                       after an `@`");
-        }
-
         match pat.node {
-            PatKind::Binding(_, _, Some(_)) => {
-                let bindings_were_allowed = self.bindings_allowed;
-                self.bindings_allowed = false;
-                intravisit::walk_pat(self, pat);
-                self.bindings_allowed = bindings_were_allowed;
+            PatKind::Binding(_, _, ref subpat) => {
+                if !self.bindings_allowed {
+                    span_err!(self.cx.tcx.sess, pat.span, E0303,
+                              "pattern bindings are not allowed after an `@`");
+                }
+
+                if subpat.is_some() {
+                    let bindings_were_allowed = self.bindings_allowed;
+                    self.bindings_allowed = false;
+                    intravisit::walk_pat(self, pat);
+                    self.bindings_allowed = bindings_were_allowed;
+                }
             }
             _ => intravisit::walk_pat(self, pat),
         }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index d1595f243c9..b765043da88 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -43,7 +43,7 @@ impl UnusedMut {
 
         let mut mutables = FnvHashMap();
         for p in pats {
-            pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path1| {
+            pat_util::pat_bindings(p, |mode, id, _, path1| {
                 let name = path1.node;
                 if let hir::BindByValue(hir::MutMutable) = mode {
                     if !name.as_str().starts_with("_") {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 1e7164a62c0..1f560672b62 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -656,7 +656,7 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         None
     } else {
         map = FnvHashMap();
-        pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
+        pat_util::pat_bindings(&arm.pats[0], |_, p_id, _, path| {
             map.insert(path.node, p_id);
         });
         Some(&map)
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index bdde5ce1617..419e19532dd 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -540,7 +540,6 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
 }
 
 fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                     dm: &RefCell<DefMap>,
                                      m: &[Match<'a, 'p, 'blk, 'tcx>],
                                      col: usize,
                                      val: MatchInput)
@@ -551,12 +550,13 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Collect all of the matches that can match against anything.
     enter_match(bcx, m, col, val, |pats| {
-        if pat_is_binding_or_wild(&dm.borrow(), &pats[col]) {
-            let mut r = pats[..col].to_vec();
-            r.extend_from_slice(&pats[col + 1..]);
-            Some(r)
-        } else {
-            None
+        match pats[col].node {
+            PatKind::Binding(..) | PatKind::Wild => {
+                let mut r = pats[..col].to_vec();
+                r.extend_from_slice(&pats[col + 1..]);
+                Some(r)
+            }
+            _ => None
         }
     })
 }
@@ -1145,7 +1145,6 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                                  has_genuine_default: bool) {
     let fcx = bcx.fcx;
     let tcx = bcx.tcx();
-    let dm = &tcx.def_map;
 
     let mut vals_left = vals[0..col].to_vec();
     vals_left.extend_from_slice(&vals[col + 1..]);
@@ -1279,7 +1278,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         C_int(ccx, 0) // Placeholder for when not using a switch
     };
 
-    let defaults = enter_default(else_cx, dm, m, col, val);
+    let defaults = enter_default(else_cx, m, col, val);
     let exhaustive = chk.is_infallible() && defaults.is_empty();
     let len = opts.len();
 
@@ -1509,10 +1508,9 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &hir::Pat,
     // Note that we use the names because each binding will have many ids
     // from the various alternatives.
     let ccx = bcx.ccx();
-    let tcx = bcx.tcx();
     let reassigned = is_discr_reassigned(bcx, discr, body);
     let mut bindings_map = FnvHashMap();
-    pat_bindings(&tcx.def_map, &pat, |bm, p_id, span, path1| {
+    pat_bindings(&pat, |bm, p_id, span, path1| {
         let name = path1.node;
         let variable_ty = node_id_type(bcx, p_id);
         let llvariable_ty = type_of::type_of(ccx, variable_ty);
@@ -1655,7 +1653,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         // create dummy memory for the variables if we have no
         // value to store into them immediately
         let tcx = bcx.tcx();
-        pat_bindings(&tcx.def_map, pat, |_, p_id, _, path1| {
+        pat_bindings(pat, |_, p_id, _, path1| {
             let scope = cleanup::var_scope(tcx, p_id);
             bcx = mk_binding_alloca(
                 bcx, p_id, path1.node, scope, (),
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index 66409a4c481..bba0edd5f04 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -42,16 +42,13 @@ pub fn create_scope_map(cx: &CrateContext,
                         fn_ast_id: ast::NodeId)
                         -> NodeMap<DIScope> {
     let mut scope_map = NodeMap();
-
-    let def_map = &cx.tcx().def_map;
-
     let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None });
     scope_map.insert(fn_ast_id, fn_metadata);
 
     // Push argument identifiers onto the stack so arguments integrate nicely
     // with variable shadowing.
     for arg in args {
-        pat_util::pat_bindings(def_map, &arg.pat, |_, node_id, _, path1| {
+        pat_util::pat_bindings(&arg.pat, |_, node_id, _, path1| {
             scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
                                                name: Some(path1.node.unhygienize()) });
             scope_map.insert(node_id, fn_metadata);
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index b401166cfdb..ab4860dff15 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1889,11 +1889,8 @@ pub fn create_local_var_metadata(bcx: Block, local: &hir::Local) {
         return;
     }
 
-    let cx = bcx.ccx();
-    let def_map = &cx.tcx().def_map;
     let locals = bcx.fcx.lllocals.borrow();
-
-    pat_util::pat_bindings(def_map, &local.pat, |_, node_id, span, var_name| {
+    pat_util::pat_bindings(&local.pat, |_, node_id, span, var_name| {
         let datum = match locals.get(&node_id) {
             Some(datum) => datum,
             None => {
@@ -2062,7 +2059,6 @@ pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) {
         return;
     }
 
-    let def_map = &bcx.tcx().def_map;
     let scope_metadata = bcx
                          .fcx
                          .debug_context
@@ -2070,7 +2066,7 @@ pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) {
                          .fn_metadata;
     let locals = bcx.fcx.lllocals.borrow();
 
-    pat_util::pat_bindings(def_map, &arg.pat, |_, node_id, span, var_name| {
+    pat_util::pat_bindings(&arg.pat, |_, node_id, span, var_name| {
         let datum = match locals.get(&node_id) {
             Some(v) => v,
             None => {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 31805f14a8c..99b443e2924 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -10,7 +10,7 @@
 
 use hir::def::{self, Def};
 use rustc::infer::{self, InferOk, TypeOrigin};
-use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
+use hir::pat_util::{PatIdMap, pat_id_map};
 use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
@@ -436,23 +436,19 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
-        let tcx = self.tcx;
-        if pat_is_binding(&tcx.def_map.borrow(), inner) {
-            let expected = self.shallow_resolve(expected);
-            expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty {
-                ty::TyTrait(_) => {
+        if let PatKind::Binding(..) = inner.node {
+            if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
+                if let ty::TyTrait(..) = mt.ty.sty {
                     // This is "x = SomeTrait" being reduced from
                     // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
-                    span_err!(tcx.sess, span, E0033,
+                    span_err!(self.tcx.sess, span, E0033,
                               "type `{}` cannot be dereferenced",
                               self.ty_to_string(expected));
-                    false
+                    return false
                 }
-                _ => true
-            })
-        } else {
-            true
+            }
         }
+        true
     }
 }
 
@@ -491,7 +487,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         for arm in arms {
             let pcx = PatCtxt {
                 fcx: self,
-                map: pat_id_map(&tcx.def_map, &arm.pats[0]),
+                map: pat_id_map(&arm.pats[0]),
             };
             for p in &arm.pats {
                 pcx.check_pat(&p, discrim_ty);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 85a5d5b6293..819448e6a80 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -630,8 +630,6 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                             body: &'gcx hir::Block)
                             -> FnCtxt<'a, 'gcx, 'tcx>
 {
-    let tcx = inherited.tcx;
-
     let arg_tys = &fn_sig.inputs;
     let ret_ty = fn_sig.output;
 
@@ -667,19 +665,15 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
             fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
 
             // Create type variables for each argument.
-            pat_util::pat_bindings(
-                &tcx.def_map,
-                &input.pat,
-                |_bm, pat_id, sp, _path| {
-                    let var_ty = visit.assign(sp, pat_id, None);
-                    fcx.require_type_is_sized(var_ty, sp,
-                                              traits::VariableType(pat_id));
-                });
+            pat_util::pat_bindings(&input.pat, |_bm, pat_id, sp, _path| {
+                let var_ty = visit.assign(sp, pat_id, None);
+                fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
+            });
 
             // Check the pattern.
             let pcx = PatCtxt {
                 fcx: &fcx,
-                map: pat_id_map(&tcx.def_map, &input.pat),
+                map: pat_id_map(&input.pat),
             };
             pcx.check_pat(&input.pat, *arg_ty);
         }
@@ -3932,8 +3926,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
-        let tcx = self.tcx;
-
         let t = self.local_ty(local.span, local.id);
         self.write_ty(local.id, t);
 
@@ -3947,7 +3939,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let pcx = PatCtxt {
             fcx: self,
-            map: pat_id_map(&tcx.def_map, &local.pat),
+            map: pat_id_map(&local.pat),
         };
         pcx.check_pat(&local.pat, t);
         let pat_ty = self.node_ty(local.pat.id);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index bf34428832d..fd1b6055173 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -452,7 +452,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
         let tcx = self.tcx;
         debug!("regionck::visit_pat(pat={:?})", pat);
-        pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
+        pat_util::pat_bindings(pat, |_, id, span, _| {
             // If we have a variable that contains region'd data, that
             // data will be accessible from anywhere that the variable is
             // accessed. We must be wary of loops like this:
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index e6500747c05..205eaf1a38e 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -15,7 +15,6 @@ use self::ResolveReason::*;
 
 use check::FnCtxt;
 use hir::def_id::DefId;
-use hir::pat_util;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{TypeFolder,TypeFoldable};
@@ -29,7 +28,7 @@ use syntax::ast;
 use syntax::codemap::{DUMMY_SP, Span};
 use rustc::hir::print::pat_to_string;
 use rustc::hir::intravisit::{self, Visitor};
-use rustc::hir;
+use rustc::hir::{self, PatKind};
 
 ///////////////////////////////////////////////////////////////////////////
 // Entry point functions
@@ -54,9 +53,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             wbcx.visit_pat(&arg.pat);
 
             // Privacy needs the type for the whole pattern, not just each binding
-            if !pat_util::pat_is_binding(&self.tcx.def_map.borrow(), &arg.pat) {
-                wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
-                                   arg.pat.id);
+            if let PatKind::Binding(..) = arg.pat.node {} else {
+                wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
             }
         }
         wbcx.visit_upvar_borrow_map();
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 9ecaa5b346a..be8d296dab0 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -616,14 +616,10 @@ pub enum PatKind {
     /// Represents a wildcard pattern (`_`)
     Wild,
 
-    /// A `PatKind::Ident` may either be a new bound variable,
-    /// or a unit struct/variant pattern, or a const pattern (in the last two cases
-    /// the third field must be `None`).
-    ///
-    /// In the unit or const pattern case, the parser can't determine
-    /// which it is. The resolver determines this, and
-    /// records this pattern's `NodeId` in an auxiliary
-    /// set (of "PatIdents that refer to unit patterns or constants").
+    /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
+    /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
+    /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
+    /// during name resolution.
     Ident(BindingMode, SpannedIdent, Option<P<Pat>>),
 
     /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
@@ -639,10 +635,8 @@ pub enum PatKind {
     /// Such pattern can be resolved to a unit struct/variant or a constant.
     Path(Path),
 
-    /// An associated const named using the qualified path `<T>::CONST` or
-    /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
-    /// referred to as simply `T::CONST`, in which case they will end up as
-    /// PatKind::Path, and the resolver will have to sort that out.
+    /// A path pattern written in qualified form, i.e. `<T as Trait>::CONST` or `<T>::CONST`.
+    /// Such patterns can only refer to associated constants at the moment.
     QPath(QSelf, Path),
 
     /// A tuple pattern `(a, b)`.