about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/construct.rs27
-rw-r--r--src/librustc/hir/def.rs8
-rw-r--r--src/librustc/hir/intravisit.rs22
-rw-r--r--src/librustc/hir/lowering.rs260
-rw-r--r--src/librustc/hir/map/def_collector.rs2
-rw-r--r--src/librustc/hir/map/mod.rs2
-rw-r--r--src/librustc/hir/mod.rs45
-rw-r--r--src/librustc/hir/pat_util.rs245
-rw-r--r--src/librustc/hir/print.rs16
-rw-r--r--src/librustc/infer/error_reporting.rs3
-rw-r--r--src/librustc/middle/astconv_util.rs2
-rw-r--r--src/librustc/middle/dead.rs33
-rw-r--r--src/librustc/middle/effect.rs4
-rw-r--r--src/librustc/middle/expr_use_visitor.rs30
-rw-r--r--src/librustc/middle/intrinsicck.rs9
-rw-r--r--src/librustc/middle/liveness.rs59
-rw-r--r--src/librustc/middle/mem_categorization.rs37
-rw-r--r--src/librustc/middle/reachable.rs59
-rw-r--r--src/librustc/middle/resolve_lifetime.rs12
-rw-r--r--src/librustc/middle/stability.rs25
-rw-r--r--src/librustc/ty/context.rs23
-rw-r--r--src/librustc/ty/mod.rs26
-rw-r--r--src/librustc/ty/util.rs9
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_const_eval/_match.rs11
-rw-r--r--src/librustc_const_eval/check_match.rs50
-rw-r--r--src/librustc_const_eval/eval.rs74
-rw-r--r--src/librustc_const_eval/pattern.rs32
-rw-r--r--src/librustc_driver/driver.rs9
-rw-r--r--src/librustc_driver/test.rs3
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs20
-rw-r--r--src/librustc_lint/bad_style.rs15
-rw-r--r--src/librustc_lint/builtin.rs37
-rw-r--r--src/librustc_lint/unused.rs3
-rw-r--r--src/librustc_metadata/astencode.rs11
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_mir/build/mod.rs4
-rw-r--r--src/librustc_mir/hair/cx/expr.rs46
-rw-r--r--src/librustc_passes/consts.rs20
-rw-r--r--src/librustc_passes/loops.rs19
-rw-r--r--src/librustc_passes/static_recursion.rs19
-rw-r--r--src/librustc_privacy/lib.rs78
-rw-r--r--src/librustc_resolve/lib.rs7
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs20
-rw-r--r--src/librustc_save_analysis/lib.rs48
-rw-r--r--src/librustc_typeck/astconv.rs93
-rw-r--r--src/librustc_typeck/check/_match.rs18
-rw-r--r--src/librustc_typeck/check/callee.rs14
-rw-r--r--src/librustc_typeck/check/mod.rs138
-rw-r--r--src/librustc_typeck/check/regionck.rs3
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs45
-rw-r--r--src/librustdoc/visit_ast.rs22
-rw-r--r--src/test/compile-fail/issue-3521.rs2
55 files changed, 927 insertions, 925 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 609d492a93a..f21d98a0fc7 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -10,8 +10,6 @@
 
 use rustc_data_structures::graph;
 use cfg::*;
-use hir::def::Def;
-use hir::pat_util;
 use ty::{self, TyCtxt};
 use syntax::ast;
 use syntax::ptr::P;
@@ -284,7 +282,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
             hir::ExprBreak(label, ref opt_expr) => {
                 let v = self.opt_expr(opt_expr, pred);
-                let loop_scope = self.find_scope(expr, label.map(|l| l.node));
+                let loop_scope = self.find_scope(expr, label);
                 let b = self.add_ast_node(expr.id, &[v]);
                 self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
@@ -292,7 +290,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprAgain(label) => {
-                let loop_scope = self.find_scope(expr, label.map(|l| l.node));
+                let loop_scope = self.find_scope(expr, label);
                 let a = self.add_ast_node(expr.id, &[pred]);
                 self.add_exiting_edge(expr, a,
                                       loop_scope, loop_scope.continue_index);
@@ -457,7 +455,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(&pat);
+                    let this_has_bindings = pat.contains_bindings_or_wild();
 
                     // If both this pattern and the previous pattern
                     // were free of bindings, they must consist only
@@ -570,23 +568,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
     fn find_scope(&self,
                   expr: &hir::Expr,
-                  label: Option<ast::Name>) -> LoopScope {
-        if label.is_none() {
-            return *self.loop_scopes.last().unwrap();
-        }
-
-        match self.tcx.expect_def(expr.id) {
-            Def::Label(loop_id) => {
+                  label: Option<hir::Label>) -> LoopScope {
+        match label {
+            None => *self.loop_scopes.last().unwrap(),
+            Some(label) => {
                 for l in &self.loop_scopes {
-                    if l.loop_id == loop_id {
+                    if l.loop_id == label.loop_id {
                         return *l;
                     }
                 }
-                span_bug!(expr.span, "no loop scope for id {}", loop_id);
-            }
-
-            r => {
-                span_bug!(expr.span, "bad entry `{:?}` in def_map for label", r);
+                span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
             }
         }
     }
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index feefc43f401..b6fce2d6ca0 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -83,14 +83,6 @@ impl PathResolution {
         PathResolution { base_def: def, depth: 0 }
     }
 
-    /// Get the definition, if fully resolved, otherwise panic.
-    pub fn full_def(&self) -> Def {
-        if self.depth != 0 {
-            bug!("path not fully resolved: {:?}", self);
-        }
-        self.base_def
-    }
-
     pub fn kind_name(&self) -> &'static str {
         if self.depth != 0 {
             "associated item"
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 3de788b8c1a..94da10d33f8 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -38,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
+use hir::def::Def;
 use hir::map::Map;
 use super::itemlikevisit::DeepVisitor;
 
@@ -155,6 +156,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_id(&mut self, _node_id: NodeId) {
         // Nothing to do.
     }
+    fn visit_def_mention(&mut self, _def: Def) {
+        // Nothing to do.
+    }
     fn visit_name(&mut self, _span: Span, _name: Name) {
         // Nothing to do.
     }
@@ -507,6 +511,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath, id: Nod
 }
 
 pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
+    visitor.visit_def_mention(path.def);
     for segment in &path.segments {
         visitor.visit_path_segment(path.span, segment);
     }
@@ -566,7 +571,8 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
         PatKind::Ref(ref subpattern, _) => {
             visitor.visit_pat(subpattern)
         }
-        PatKind::Binding(_, ref pth1, ref optional_subpattern) => {
+        PatKind::Binding(_, def_id, ref pth1, ref optional_subpattern) => {
+            visitor.visit_def_mention(Def::Local(def_id));
             visitor.visit_name(pth1.span, pth1.node);
             walk_list!(visitor, visit_pat, optional_subpattern);
         }
@@ -907,12 +913,18 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref qpath) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
         }
-        ExprBreak(ref opt_sp_name, ref opt_expr) => {
-            walk_opt_sp_name(visitor, opt_sp_name);
+        ExprBreak(None, ref opt_expr) => {
             walk_list!(visitor, visit_expr, opt_expr);
         }
-        ExprAgain(ref opt_sp_name) => {
-            walk_opt_sp_name(visitor, opt_sp_name);
+        ExprBreak(Some(label), ref opt_expr) => {
+            visitor.visit_def_mention(Def::Label(label.loop_id));
+            visitor.visit_name(label.span, label.name);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprAgain(None) => {}
+        ExprAgain(Some(label)) => {
+            visitor.visit_def_mention(Def::Label(label.loop_id));
+            visitor.visit_name(label.span, label.name);
         }
         ExprRet(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index af0448cc277..aea05357a84 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -77,7 +77,7 @@ pub struct LoweringContext<'a> {
 
 pub trait Resolver {
     // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc.
-    fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def;
+    fn resolve_generated_global_path(&mut self, path: &mut hir::Path, is_value: bool);
 
     // Obtain the resolution for a node id
     fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
@@ -154,6 +154,15 @@ impl<'a> LoweringContext<'a> {
         self.sess.next_node_id()
     }
 
+    fn expect_full_def(&mut self, id: NodeId) -> Def {
+        self.resolver.get_resolution(id).map_or(Def::Err, |pr| {
+            if pr.depth != 0 {
+                bug!("path not fully resolved: {:?}", pr);
+            }
+            pr.base_def
+        })
+    }
+
     fn diagnostic(&self) -> &errors::Handler {
         self.sess.diagnostic()
     }
@@ -181,6 +190,19 @@ impl<'a> LoweringContext<'a> {
         o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
     }
 
+    fn lower_label(&mut self, id: NodeId, label: Option<Spanned<Ident>>) -> Option<hir::Label> {
+        label.map(|sp_ident| {
+            hir::Label {
+                span: sp_ident.span,
+                name: sp_ident.node.name,
+                loop_id: match self.expect_full_def(id) {
+                    Def::Label(loop_id) => loop_id,
+                    _ => DUMMY_NODE_ID
+                }
+            }
+        })
+    }
+
     fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
         attrs.clone().into()
     }
@@ -286,6 +308,7 @@ impl<'a> LoweringContext<'a> {
         let proj_start = p.segments.len() - resolution.depth;
         let path = P(hir::Path {
             global: p.global,
+            def: resolution.base_def,
             segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| {
                 let param_mode = match (qself_position, param_mode) {
                     (Some(j), ParamMode::Optional) if i < j => {
@@ -353,12 +376,14 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_path_extra(&mut self,
+                        id: NodeId,
                         p: &Path,
                         name: Option<Name>,
                         param_mode: ParamMode)
                         -> hir::Path {
         hir::Path {
             global: p.global,
+            def: self.expect_full_def(id),
             segments: p.segments.iter().map(|segment| {
                 self.lower_path_segment(segment, param_mode)
             }).chain(name.map(|name| {
@@ -372,10 +397,11 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_path(&mut self,
+                  id: NodeId,
                   p: &Path,
                   param_mode: ParamMode)
                   -> hir::Path {
-        self.lower_path_extra(p, None, param_mode)
+        self.lower_path_extra(id, p, None, param_mode)
     }
 
     fn lower_path_segment(&mut self,
@@ -569,7 +595,7 @@ impl<'a> LoweringContext<'a> {
                                                           span}) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     id: id,
-                    path: self.lower_path(path, ParamMode::Explicit),
+                    path: self.lower_path(id, path, ParamMode::Explicit),
                     ty: self.lower_ty(ty),
                     span: span,
                 })
@@ -599,7 +625,7 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
         hir::TraitRef {
-            path: self.lower_path(&p.path, ParamMode::Explicit),
+            path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit),
             ref_id: p.ref_id,
         }
     }
@@ -665,6 +691,7 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_item_kind(&mut self,
+                       id: NodeId,
                        name: &mut Name,
                        attrs: &hir::HirVec<Attribute>,
                        vis: &mut hir::Visibility,
@@ -690,7 +717,7 @@ impl<'a> LoweringContext<'a> {
                                 Some(ident.name)
                             };
 
-                            let mut path = self.lower_path_extra(path, suffix,
+                            let mut path = self.lower_path_extra(import.id, path, suffix,
                                                                  ParamMode::Explicit);
                             path.span = span;
                             self.items.insert(import.id, hir::Item {
@@ -705,7 +732,7 @@ impl<'a> LoweringContext<'a> {
                         path
                     }
                 };
-                let path = P(self.lower_path(path, ParamMode::Explicit));
+                let path = P(self.lower_path(id, path, ParamMode::Explicit));
                 let kind = match view_path.node {
                     ViewPathSimple(ident, _) => {
                         *name = ident.name;
@@ -901,7 +928,7 @@ impl<'a> LoweringContext<'a> {
         let attrs = self.lower_attrs(&i.attrs);
         let mut vis = self.lower_visibility(&i.vis);
         let node = self.with_parent_def(i.id, |this| {
-            this.lower_item_kind(&mut name, &attrs, &mut vis, &i.node)
+            this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node)
         });
 
         hir::Item {
@@ -1012,14 +1039,24 @@ impl<'a> LoweringContext<'a> {
                     self.with_parent_def(p.id, |this| {
                         match this.resolver.get_resolution(p.id).map(|d| d.base_def) {
                             // `None` can occur in body-less function signatures
-                            None | Some(Def::Local(..)) => {
+                            def @ None | def @ Some(Def::Local(_)) => {
+                                let def_id = def.map(|d| d.def_id()).unwrap_or_else(|| {
+                                    this.resolver.definitions().local_def_id(p.id)
+                                });
                                 hir::PatKind::Binding(this.lower_binding_mode(binding_mode),
+                                                      def_id,
                                                       respan(pth1.span, pth1.node.name),
                                                       sub.as_ref().map(|x| this.lower_pat(x)))
                             }
-                            _ => {
-                                let path = hir::Path::from_name(pth1.span, pth1.node.name);
-                                hir::PatKind::Path(hir::QPath::Resolved(None, P(path)))
+                            Some(def) => {
+                                hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
+                                    span: pth1.span,
+                                    global: false,
+                                    def: def,
+                                    segments: hir_vec![
+                                        hir::PathSegment::from_name(pth1.node.name)
+                                    ],
+                                })))
                             }
                         }
                     })
@@ -1120,8 +1157,7 @@ impl<'a> LoweringContext<'a> {
                     let inplace_finalize = ["ops", "InPlace", "finalize"];
 
                     let make_call = |this: &mut LoweringContext, p, args| {
-                        let path = this.std_path(e.span, p);
-                        let path = this.expr_path(path, ThinVec::new());
+                        let path = this.expr_std_path(e.span, p, ThinVec::new());
                         P(this.expr_call(e.span, path, args))
                     };
 
@@ -1315,13 +1351,12 @@ impl<'a> LoweringContext<'a> {
                                    ast_expr: &Expr,
                                    path: &[&str],
                                    fields: &[(&str, &P<Expr>)]) -> hir::Expr {
-                        let struct_path = this.std_path(ast_expr.span,
-                                                        &iter::once(&"ops").chain(path)
-                                                                           .map(|s| *s)
-                                                                           .collect::<Vec<_>>());
+                        let struct_path = &iter::once(&"ops").chain(path).map(|s| *s)
+                                                             .collect::<Vec<_>>();
 
                         let hir_expr = if fields.len() == 0 {
-                            this.expr_path(struct_path, ast_expr.attrs.clone())
+                            this.expr_std_path(ast_expr.span, struct_path,
+                                               ast_expr.attrs.clone())
                         } else {
                             let fields = fields.into_iter().map(|&(s, e)| {
                                 let expr = P(this.lower_expr(&e));
@@ -1334,7 +1369,7 @@ impl<'a> LoweringContext<'a> {
                             }).collect();
                             let attrs = ast_expr.attrs.clone();
 
-                            this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
+                            this.expr_std_struct(ast_expr.span, struct_path, fields, None, attrs)
                         };
 
                         this.signal_block_expr(hir_vec![],
@@ -1378,10 +1413,10 @@ impl<'a> LoweringContext<'a> {
                     hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
                 }
                 ExprKind::Break(opt_ident, ref opt_expr) => {
-                    hir::ExprBreak(self.lower_opt_sp_ident(opt_ident),
+                    hir::ExprBreak(self.lower_label(e.id, opt_ident),
                                    opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
                 }
-                ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)),
+                ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)),
                 ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
                 ExprKind::InlineAsm(ref asm) => {
                     let hir_asm = hir::InlineAsm {
@@ -1608,10 +1643,10 @@ impl<'a> LoweringContext<'a> {
 
                     // `match ::std::iter::Iterator::next(&mut iter) { ... }`
                     let match_expr = {
-                        let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
                         let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
                         let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
-                        let next_path = self.expr_path(next_path, ThinVec::new());
+                        let next_path = &["iter", "Iterator", "next"];
+                        let next_path = self.expr_std_path(e.span, next_path, ThinVec::new());
                         let next_expr = P(self.expr_call(e.span, next_path,
                                           hir_vec![ref_mut_iter]));
                         let arms = hir_vec![pat_arm, break_arm];
@@ -1638,10 +1673,8 @@ impl<'a> LoweringContext<'a> {
 
                     // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                     let into_iter_expr = {
-                        let into_iter_path = self.std_path(e.span,
-                                                           &["iter", "IntoIterator", "into_iter"]);
-
-                        let into_iter = self.expr_path(into_iter_path, ThinVec::new());
+                        let into_iter_path = &["iter", "IntoIterator", "into_iter"];
+                        let into_iter = self.expr_std_path(e.span, into_iter_path, ThinVec::new());
                         P(self.expr_call(e.span, into_iter, hir_vec![head]))
                     };
 
@@ -1684,8 +1717,8 @@ impl<'a> LoweringContext<'a> {
                                                               hir::PopUnstableBlock,
                                                               ThinVec::new());
 
-                        let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
-                        let path = self.expr_path(path, ThinVec::new());
+                        let path = &["ops", "Carrier", "translate"];
+                        let path = self.expr_std_path(e.span,path, ThinVec::new());
                         let call = P(self.expr_call(e.span, path, hir_vec![sub_expr]));
 
                         P(self.signal_block_expr(hir_vec![],
@@ -1710,15 +1743,15 @@ impl<'a> LoweringContext<'a> {
                         let err_ident = self.str_to_ident("err");
                         let err_local = self.pat_ident(e.span, err_ident);
                         let from_expr = {
-                            let path = self.std_path(e.span, &["convert", "From", "from"]);
-                            let from = self.expr_path(path, ThinVec::new());
+                            let path = &["convert", "From", "from"];
+                            let from = self.expr_std_path(e.span, path, ThinVec::new());
                             let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
 
                             self.expr_call(e.span, from, hir_vec![err_expr])
                         };
                         let from_err_expr = {
-                            let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
-                            let from_err = self.expr_path(path, ThinVec::new());
+                            let path = &["ops", "Carrier", "from_error"];
+                            let from_err = self.expr_std_path(e.span, path, ThinVec::new());
                             P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
                         };
 
@@ -1794,7 +1827,7 @@ impl<'a> LoweringContext<'a> {
             Visibility::Crate(_) => hir::Visibility::Crate,
             Visibility::Restricted { ref path, id } => {
                 hir::Visibility::Restricted {
-                    path: P(self.lower_path(path, ParamMode::Explicit)),
+                    path: P(self.lower_path(id, path, ParamMode::Explicit)),
                     id: id
                 }
             }
@@ -1880,14 +1913,18 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
-        let path = self.path_ident(span, id);
-        let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(path)));
-        let expr = self.expr(span, expr_path, ThinVec::new());
-
         let def = {
             let defs = self.resolver.definitions();
             Def::Local(defs.local_def_id(binding))
         };
+
+        let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path {
+            span: span,
+            global: false,
+            def: def,
+            segments: hir_vec![hir::PathSegment::from_name(id)],
+        })));
+        let expr = self.expr(span, expr_path, ThinVec::new());
         self.resolver.record_resolution(expr.id, def);
 
         expr
@@ -1897,9 +1934,14 @@ impl<'a> LoweringContext<'a> {
         self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new())
     }
 
-    fn expr_path(&mut self, path: hir::Path, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        let def = self.resolver.resolve_generated_global_path(&path, true);
-        let expr = self.expr(path.span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs);
+    fn expr_std_path(&mut self,
+                     span: Span,
+                     components: &[&str],
+                     attrs: ThinVec<Attribute>)
+                     -> P<hir::Expr> {
+        let path = self.std_path(span, components, true);
+        let def = path.def;
+        let expr = self.expr(span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs);
         self.resolver.record_resolution(expr.id, def);
         P(expr)
     }
@@ -1921,15 +1963,16 @@ impl<'a> LoweringContext<'a> {
         P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new()))
     }
 
-    fn expr_struct(&mut self,
-                   sp: Span,
-                   path: hir::Path,
-                   fields: hir::HirVec<hir::Field>,
-                   e: Option<P<hir::Expr>>,
-                   attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        let def = self.resolver.resolve_generated_global_path(&path, false);
+    fn expr_std_struct(&mut self,
+                       span: Span,
+                       components: &[&str],
+                       fields: hir::HirVec<hir::Field>,
+                       e: Option<P<hir::Expr>>,
+                       attrs: ThinVec<Attribute>) -> P<hir::Expr> {
+        let path = self.std_path(span, components, false);
+        let def = path.def;
         let qpath = hir::QPath::Resolved(None, P(path));
-        let expr = self.expr(sp, hir::ExprStruct(qpath, fields, e), attrs);
+        let expr = self.expr(span, hir::ExprStruct(qpath, fields, e), attrs);
         self.resolver.record_resolution(expr.id, def);
         P(expr)
     }
@@ -1988,28 +2031,28 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let path = self.std_path(span, &["result", "Result", "Ok"]);
-        self.pat_enum(span, path, hir_vec![pat])
+        self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
     }
 
     fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let path = self.std_path(span, &["result", "Result", "Err"]);
-        self.pat_enum(span, path, hir_vec![pat])
+        self.pat_std_enum(span, &["result", "Result", "Err"], hir_vec![pat])
     }
 
     fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        let path = self.std_path(span, &["option", "Option", "Some"]);
-        self.pat_enum(span, path, hir_vec![pat])
+        self.pat_std_enum(span, &["option", "Option", "Some"], hir_vec![pat])
     }
 
     fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
-        let path = self.std_path(span, &["option", "Option", "None"]);
-        self.pat_enum(span, path, hir_vec![])
+        self.pat_std_enum(span, &["option", "Option", "None"], hir_vec![])
     }
 
-    fn pat_enum(&mut self, span: Span, path: hir::Path, subpats: hir::HirVec<P<hir::Pat>>)
-                -> P<hir::Pat> {
-        let def = self.resolver.resolve_generated_global_path(&path, true);
+    fn pat_std_enum(&mut self,
+                    span: Span,
+                    components: &[&str],
+                    subpats: hir::HirVec<P<hir::Pat>>)
+                    -> P<hir::Pat> {
+        let path = self.std_path(span, components, true);
+        let def = path.def;
         let qpath = hir::QPath::Resolved(None, P(path));
         let pt = if subpats.is_empty() {
             hir::PatKind::Path(qpath)
@@ -2027,25 +2070,27 @@ impl<'a> LoweringContext<'a> {
 
     fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode)
                               -> P<hir::Pat> {
-        let pat_ident = hir::PatKind::Binding(bm,
-                                            Spanned {
-                                                span: span,
-                                                node: name,
-                                            },
-                                            None);
-
-        let pat = self.pat(span, pat_ident);
-
+        let id = self.next_id();
         let parent_def = self.parent_def;
-        let def = {
+        let def_id = {
             let defs = self.resolver.definitions();
             let def_path_data = DefPathData::Binding(name.as_str());
-            let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data);
-            Def::Local(DefId::local(def_index))
+            let def_index = defs.create_def_with_parent(parent_def, id, def_path_data);
+            DefId::local(def_index)
         };
-        self.resolver.record_resolution(pat.id, def);
+        self.resolver.record_resolution(id, Def::Local(def_id));
 
-        pat
+        P(hir::Pat {
+            id: id,
+            node: hir::PatKind::Binding(bm,
+                                        def_id,
+                                        Spanned {
+                                            span: span,
+                                            node: name,
+                                        },
+                                        None),
+            span: span,
+        })
     }
 
     fn pat_wild(&mut self, span: Span) -> P<hir::Pat> {
@@ -2060,64 +2105,25 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn path_ident(&mut self, span: Span, id: Name) -> hir::Path {
-        self.path(span, vec![id])
-    }
-
-    fn path(&mut self, span: Span, strs: Vec<Name>) -> hir::Path {
-        self.path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
-    }
-
-    fn path_global(&mut self, span: Span, strs: Vec<Name>) -> hir::Path {
-        self.path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
-    }
+    /// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+    /// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+    /// The path is also resolved according to `is_value`.
+    fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
+        let idents = self.crate_root.iter().chain(components);
 
-    fn path_all(&mut self,
-                sp: Span,
-                global: bool,
-                mut names: Vec<Name>,
-                lifetimes: hir::HirVec<hir::Lifetime>,
-                types: hir::HirVec<P<hir::Ty>>,
-                bindings: hir::HirVec<hir::TypeBinding>)
-                -> hir::Path {
-        let last_identifier = names.pop().unwrap();
-        let mut segments: Vec<hir::PathSegment> = names.into_iter().map(|name| {
-            hir::PathSegment {
-                name: name,
-                parameters: hir::PathParameters::none(),
-           }
+        let segments: Vec<_> = idents.map(|name| {
+            hir::PathSegment::from_name(Symbol::intern(name))
         }).collect();
 
-        segments.push(hir::PathSegment {
-            name: last_identifier,
-            parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
-                lifetimes: lifetimes,
-                types: types,
-                infer_types: true,
-                bindings: bindings,
-            }),
-        });
-        hir::Path {
-            span: sp,
-            global: global,
+        let mut path = hir::Path {
+            span: span,
+            global: true,
+            def: Def::Err,
             segments: segments.into(),
-        }
-    }
-
-    fn std_path_components(&mut self, components: &[&str]) -> Vec<Name> {
-        let mut v = Vec::new();
-        if let Some(s) = self.crate_root {
-            v.push(Symbol::intern(s));
-        }
-        v.extend(components.iter().map(|s| Symbol::intern(s)));
-        return v;
-    }
+        };
 
-    // Given suffix ["b","c","d"], returns path `::std::b::c::d` when
-    // `fld.cx.use_std`, and `::core::b::c::d` otherwise.
-    fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
-        let idents = self.std_path_components(components);
-        self.path_global(span, idents)
+        self.resolver.resolve_generated_global_path(&mut path, is_value);
+        path
     }
 
     fn signal_block_expr(&mut self,
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 9d1c7d41faa..a08060e7927 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -436,7 +436,7 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
     fn visit_pat(&mut self, pat: &'ast hir::Pat) {
         let parent_def = self.parent_def;
 
-        if let hir::PatKind::Binding(_, name, _) = pat.node {
+        if let hir::PatKind::Binding(_, _, name, _) = pat.node {
             let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str()));
             self.parent_def = Some(def);
         }
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index a8986530d1d..c4ed98ce6e0 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -658,7 +658,7 @@ impl<'ast> Map<'ast> {
             NodeVariant(v) => v.node.name,
             NodeLifetime(lt) => lt.name,
             NodeTyParam(tp) => tp.name,
-            NodeLocal(&Pat { node: PatKind::Binding(_,l,_), .. }) => l.node,
+            NodeLocal(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node,
             NodeStructCtor(_) => self.name(self.get_parent(id)),
             _ => bug!("no name for {}", self.node_to_string(id))
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index da759b2d4da..1e70ebf5851 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -107,6 +107,8 @@ pub struct Path {
     /// A `::foo` path, is relative to the crate root rather than current
     /// module (like paths in an import).
     pub global: bool,
+    /// The definition that the path resolved to.
+    pub def: Def,
     /// The segments in the path: the things separated by `::`.
     pub segments: HirVec<PathSegment>,
 }
@@ -123,21 +125,6 @@ impl fmt::Display for Path {
     }
 }
 
-impl Path {
-    /// Convert a span and an identifier to the corresponding
-    /// 1-segment path.
-    pub fn from_name(s: Span, name: Name) -> Path {
-        Path {
-            span: s,
-            global: false,
-            segments: hir_vec![PathSegment {
-                name: name,
-                parameters: PathParameters::none()
-            }],
-        }
-    }
-}
-
 /// A segment of a path: an identifier, an optional lifetime, and a set of
 /// types.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -153,6 +140,16 @@ pub struct PathSegment {
     pub parameters: PathParameters,
 }
 
+impl PathSegment {
+    /// Convert an identifier to the corresponding segment.
+    pub fn from_name(name: Name) -> PathSegment {
+        PathSegment {
+            name: name,
+            parameters: PathParameters::none()
+        }
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum PathParameters {
     /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>`
@@ -571,7 +568,8 @@ pub enum PatKind {
     Wild,
 
     /// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
-    Binding(BindingMode, Spanned<Name>, Option<P<Pat>>),
+    /// The `DefId` is for the definition of the variable being bound.
+    Binding(BindingMode, DefId, Spanned<Name>, Option<P<Pat>>),
 
     /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
     /// The `bool` is `true` in the presence of a `..`.
@@ -944,9 +942,9 @@ pub enum Expr_ {
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break
-    ExprBreak(Option<Spanned<Name>>, Option<P<Expr>>),
+    ExprBreak(Option<Label>, Option<P<Expr>>),
     /// A `continue`, with an optional label
-    ExprAgain(Option<Spanned<Name>>),
+    ExprAgain(Option<Label>),
     /// A `return`, with an optional value to be returned
     ExprRet(Option<P<Expr>>),
 
@@ -1023,6 +1021,13 @@ pub enum LoopSource {
 
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub struct Label {
+    pub span: Span,
+    pub name: Name,
+    pub loop_id: NodeId
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum CaptureClause {
     CaptureByValue,
     CaptureByRef,
@@ -1225,7 +1230,7 @@ pub type ExplicitSelf = Spanned<SelfKind>;
 
 impl Arg {
     pub fn to_self(&self) -> Option<ExplicitSelf> {
-        if let PatKind::Binding(BindByValue(mutbl), name, _) = self.pat.node {
+        if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
             if name.node == keywords::SelfValue.name() {
                 return match self.ty.node {
                     TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
@@ -1241,7 +1246,7 @@ impl Arg {
     }
 
     pub fn is_self(&self) -> bool {
-        if let PatKind::Binding(_, name, _) = self.pat.node {
+        if let PatKind::Binding(_, _, name, _) = self.pat.node {
             name.node == keywords::SelfValue.name()
         } else {
             false
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 8e39fde367b..0190e74df69 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -8,13 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::def::*;
+use hir::def::Def;
 use hir::def_id::DefId;
 use hir::{self, PatKind};
-use ty::TyCtxt;
 use syntax::ast;
 use syntax::codemap::Spanned;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 
 use std::iter::{Enumerate, ExactSizeIterator};
 
@@ -51,144 +50,144 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
     }
 }
 
-pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
-    match pat.node {
-        PatKind::Lit(_) |
-        PatKind::Range(..) |
-        PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
-        PatKind::Path(hir::QPath::TypeRelative(..)) => true,
-
-        PatKind::TupleStruct(..) |
-        PatKind::Path(hir::QPath::Resolved(..)) |
-        PatKind::Struct(..) => {
-            match dm.get(&pat.id).map(|d| d.full_def()) {
-                Some(Def::Variant(..)) | Some(Def::VariantCtor(..)) => true,
-                _ => false
+impl hir::Pat {
+    pub fn is_refutable(&self) -> bool {
+        match self.node {
+            PatKind::Lit(_) |
+            PatKind::Range(..) |
+            PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
+            PatKind::Path(hir::QPath::TypeRelative(..)) => true,
+
+            PatKind::Path(hir::QPath::Resolved(_, ref path)) |
+            PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
+            PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
+                match path.def {
+                    Def::Variant(..) | Def::VariantCtor(..) => true,
+                    _ => false
+                }
             }
+            PatKind::Slice(..) => true,
+            _ => false
         }
-        PatKind::Slice(..) => true,
-        _ => false
     }
-}
 
-pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
-    match pat.node {
-        PatKind::Path(hir::QPath::TypeRelative(..)) => true,
-        PatKind::Path(hir::QPath::Resolved(..)) => {
-            match dm.get(&pat.id).map(|d| d.full_def()) {
-                Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
-                _ => false
+    pub fn is_const(&self) -> bool {
+        match self.node {
+            PatKind::Path(hir::QPath::TypeRelative(..)) => true,
+            PatKind::Path(hir::QPath::Resolved(_, ref path)) => {
+                match path.def {
+                    Def::Const(..) | Def::AssociatedConst(..) => true,
+                    _ => false
+                }
             }
+            _ => false
         }
-        _ => false
     }
-}
 
-/// Call `f` on every "binding" in a pattern, e.g., on `a` in
-/// `match foo() { Some(a) => (), None => () }`
-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| {
-        if let PatKind::Binding(binding_mode, ref pth, _) = p.node {
-            f(binding_mode, p.id, p.span, pth);
-        }
-        true
-    });
-}
-
-/// 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(pat: &hir::Pat) -> bool {
-    let mut contains_bindings = false;
-    pat.walk(|p| {
-        if let PatKind::Binding(..) = p.node {
-            contains_bindings = true;
-            false // there's at least one binding, can short circuit now.
-        } else {
+    /// Call `f` on every "binding" in a pattern, e.g., on `a` in
+    /// `match foo() { Some(a) => (), None => () }`
+    pub fn each_binding<F>(&self, mut f: F)
+        where F: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
+    {
+        self.walk(|p| {
+            if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
+                f(binding_mode, p.id, p.span, pth);
+            }
             true
-        }
-    });
-    contains_bindings
-}
+        });
+    }
 
-/// 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(pat: &hir::Pat) -> Option<hir::Mutability> {
-    let mut result = None;
-    pat_bindings(pat, |mode, _, _, _| {
-        if let hir::BindingMode::BindByRef(m) = mode {
-            // Pick Mutable as maximum
-            match result {
-                None | Some(hir::MutImmutable) => result = Some(m),
-                _ => (),
+    /// Checks if the pattern contains any patterns that bind something to
+    /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
+    pub fn contains_bindings(&self) -> bool {
+        let mut contains_bindings = false;
+        self.walk(|p| {
+            if let PatKind::Binding(..) = p.node {
+                contains_bindings = true;
+                false // there's at least one binding, can short circuit now.
+            } else {
+                true
             }
-        }
-    });
-    result
-}
-
-/// 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(arm: &hir::Arm) -> Option<hir::Mutability> {
-    arm.pats.iter()
-            .filter_map(|pat| pat_contains_ref_binding(pat))
-            .max_by_key(|m| match *m {
-                hir::MutMutable => 1,
-                hir::MutImmutable => 0,
-            })
-}
+        });
+        contains_bindings
+    }
 
-/// 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(pat: &hir::Pat) -> bool {
-    let mut contains_bindings = false;
-    pat.walk(|p| {
-        match p.node {
-            PatKind::Binding(..) | PatKind::Wild => {
-                contains_bindings = true;
-                false // there's at least one binding/wildcard, can short circuit now.
+    /// Checks if the pattern contains any patterns that bind something to
+    /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
+    pub fn contains_bindings_or_wild(&self) -> bool {
+        let mut contains_bindings = false;
+        self.walk(|p| {
+            match p.node {
+                PatKind::Binding(..) | PatKind::Wild => {
+                    contains_bindings = true;
+                    false // there's at least one binding/wildcard, can short circuit now.
+                }
+                _ => true
             }
-            _ => true
-        }
-    });
-    contains_bindings
-}
+        });
+        contains_bindings
+    }
 
-pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
-    match pat.node {
-        PatKind::Binding(hir::BindByValue(..), ref path1, None) => {
-            Some(path1.node)
-        }
-        _ => {
-            None
+    pub fn simple_name(&self) -> Option<ast::Name> {
+        match self.node {
+            PatKind::Binding(hir::BindByValue(..), _, ref path1, None) => {
+                Some(path1.node)
+            }
+            _ => {
+                None
+            }
         }
     }
-}
 
-pub fn def_to_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> hir::Path {
-    hir::Path::from_name(DUMMY_SP, tcx.item_name(id))
-}
+    /// Return variants that are necessary to exist for the pattern to match.
+    pub fn necessary_variants(&self) -> Vec<DefId> {
+        let mut variants = vec![];
+        self.walk(|p| {
+            match p.node {
+                PatKind::Path(hir::QPath::Resolved(_, ref path)) |
+                PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
+                PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
+                    match path.def {
+                        Def::Variant(id) |
+                        Def::VariantCtor(id, ..) => variants.push(id),
+                        _ => ()
+                    }
+                }
+                _ => ()
+            }
+            true
+        });
+        variants.sort();
+        variants.dedup();
+        variants
+    }
 
-/// Return variants that are necessary to exist for the pattern to match.
-pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
-    let mut variants = vec![];
-    pat.walk(|p| {
-        match p.node {
-            PatKind::TupleStruct(..) |
-            PatKind::Path(hir::QPath::Resolved(..)) |
-            PatKind::Struct(..) => {
-                match dm.get(&p.id).map(|d| d.full_def()) {
-                    Some(Def::Variant(id)) |
-                    Some(Def::VariantCtor(id, ..)) => variants.push(id),
-                    _ => ()
+    /// 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 contains_ref_binding(&self) -> Option<hir::Mutability> {
+        let mut result = None;
+        self.each_binding(|mode, _, _, _| {
+            if let hir::BindingMode::BindByRef(m) = mode {
+                // Pick Mutable as maximum
+                match result {
+                    None | Some(hir::MutImmutable) => result = Some(m),
+                    _ => (),
                 }
             }
-            _ => ()
-        }
-        true
-    });
-    variants.sort();
-    variants.dedup();
-    variants
+        });
+        result
+    }
+}
+
+impl hir::Arm {
+    /// 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 contains_ref_binding(&self) -> Option<hir::Mutability> {
+        self.pats.iter()
+                 .filter_map(|pat| pat.contains_ref_binding())
+                 .max_by_key(|m| match *m {
+                    hir::MutMutable => 1,
+                    hir::MutImmutable => 0,
+                 })
+    }
 }
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 4dd08def251..49a1dc92f13 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1481,11 +1481,11 @@ impl<'a> State<'a> {
             hir::ExprPath(ref qpath) => {
                 self.print_qpath(qpath, true)?
             }
-            hir::ExprBreak(opt_name, ref opt_expr) => {
+            hir::ExprBreak(opt_label, ref opt_expr) => {
                 word(&mut self.s, "break")?;
                 space(&mut self.s)?;
-                if let Some(name) = opt_name {
-                    self.print_name(name.node)?;
+                if let Some(label) = opt_label {
+                    self.print_name(label.name)?;
                     space(&mut self.s)?;
                 }
                 if let Some(ref expr) = *opt_expr {
@@ -1493,11 +1493,11 @@ impl<'a> State<'a> {
                     space(&mut self.s)?;
                 }
             }
-            hir::ExprAgain(opt_name) => {
+            hir::ExprAgain(opt_label) => {
                 word(&mut self.s, "continue")?;
                 space(&mut self.s)?;
-                if let Some(name) = opt_name {
-                    self.print_name(name.node)?;
+                if let Some(label) = opt_label {
+                    self.print_name(label.name)?;
                     space(&mut self.s)?
                 }
             }
@@ -1782,7 +1782,7 @@ impl<'a> State<'a> {
         // is that it doesn't matter
         match pat.node {
             PatKind::Wild => word(&mut self.s, "_")?,
-            PatKind::Binding(binding_mode, ref path1, ref sub) => {
+            PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
                 match binding_mode {
                     hir::BindByRef(mutbl) => {
                         self.word_nbsp("ref")?;
@@ -2185,7 +2185,7 @@ impl<'a> State<'a> {
                 if let Some(eself) = input.to_self() {
                     self.print_explicit_self(&eself)?;
                 } else {
-                    let invalid = if let PatKind::Binding(_, name, _) = input.pat.node {
+                    let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
                         name.node == keywords::Invalid.name()
                     } else {
                         false
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 406d345992a..90d752ae6ee 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1441,7 +1441,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                     ty_queue.push(&mut_ty.ty);
                 }
                 hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
-                    match self.tcx.expect_def(cur_ty.id) {
+                    match path.def {
                         Def::Enum(did) | Def::TyAlias(did) |
                         Def::Struct(did) | Def::Union(did) => {
                             let generics = self.tcx.item_generics(did);
@@ -1621,6 +1621,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
         hir::Path {
             span: path.span,
             global: path.global,
+            def: path.def,
             segments: new_segs.into()
         }
     }
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index 5b0f241f8a8..3418034b069 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -71,7 +71,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// to it.
     pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
         if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
-            if let Def::PrimTy(nty) = self.expect_def(ast_ty.id) {
+            if let Def::PrimTy(nty) = path.def {
                 Some(self.prim_ty_to_ty(&path.segments, nty))
             } else {
                 None
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index ec064e264ab..618e2b05f13 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -14,7 +14,7 @@
 
 use dep_graph::DepNode;
 use hir::map as ast_map;
-use hir::{self, pat_util, PatKind};
+use hir::{self, PatKind};
 use hir::intravisit::{self, Visitor};
 use hir::itemlikevisit::ItemLikeVisitor;
 
@@ -86,9 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
-        let def = self.tcx.expect_def(id);
-
+    fn handle_definition(&mut self, id: ast::NodeId, def: Def) {
         // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar`
         match def {
             Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
@@ -147,12 +145,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
+    fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def,
                                   pats: &[codemap::Spanned<hir::FieldPat>]) {
         let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty {
-            ty::TyAdt(adt, _) => {
-                adt.variant_of_def(self.tcx.expect_def(lhs.id))
-            }
+            ty::TyAdt(adt, _) => adt.variant_of_def(def),
             _ => span_bug!(lhs.span, "non-ADT in struct pattern")
         };
         for pat in pats {
@@ -240,8 +236,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
-            hir::ExprPath(hir::QPath::TypeRelative(..)) => {
-                self.lookup_and_handle_definition(expr.id);
+            hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
+                let def = self.tcx.tables().qpath_def(qpath, expr.id);
+                self.handle_definition(expr.id, def);
             }
             hir::ExprMethodCall(..) => {
                 self.lookup_and_handle_method(expr.id);
@@ -260,8 +257,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
 
     fn visit_arm(&mut self, arm: &hir::Arm) {
         if arm.pats.len() == 1 {
-            let pat = &*arm.pats[0];
-            let variants = pat_util::necessary_variants(&self.tcx.def_map.borrow(), pat);
+            let variants = arm.pats[0].necessary_variants();
 
             // Inside the body, ignore constructions of variants
             // necessary for the pattern to match. Those construction sites
@@ -276,14 +272,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn visit_pat(&mut self, pat: &hir::Pat) {
-        let def_map = &self.tcx.def_map;
         match pat.node {
-            PatKind::Struct(_, ref fields, _) => {
-                self.handle_field_pattern_match(pat, fields);
+            PatKind::Struct(hir::QPath::Resolved(_, ref path), ref fields, _) => {
+                self.handle_field_pattern_match(pat, path.def, fields);
             }
-            _ if pat_util::pat_is_const(&def_map.borrow(), pat) => {
-                // it might be the only use of a const
-                self.lookup_and_handle_definition(pat.id)
+            PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
+                let def = self.tcx.tables().qpath_def(qpath, pat.id);
+                self.handle_definition(pat.id, def);
             }
             _ => ()
         }
@@ -294,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
-        self.lookup_and_handle_definition(id);
+        self.handle_definition(id, path.def);
         intravisit::walk_path(self, path);
     }
 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 2892f249c5e..ad3607a5bb8 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -186,8 +186,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             hir::ExprInlineAsm(..) => {
                 self.require_unsafe(expr.span, "use of inline assembly");
             }
-            hir::ExprPath(hir::QPath::Resolved(..)) => {
-                if let Def::Static(def_id, mutbl) = self.tcx.expect_def(expr.id) {
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                if let Def::Static(def_id, mutbl) = path.def {
                     if mutbl {
                         self.require_unsafe(expr.span, "use of mutable static");
                     } else if match self.tcx.map.get_if_local(def_id) {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 6c952825554..01d5792441f 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -19,7 +19,6 @@ pub use self::MatchMode::*;
 use self::TrackMatchMode::*;
 use self::OverloadedCallType::*;
 
-use hir::pat_util;
 use hir::def::Def;
 use hir::def_id::{DefId};
 use infer::InferCtxt;
@@ -622,7 +621,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         match local.init {
             None => {
                 let delegate = &mut self.delegate;
-                pat_util::pat_bindings(&local.pat, |_, id, span, _| {
+                local.pat.each_binding(|_, id, span, _| {
                     delegate.decl_without_init(id, span);
                 })
             }
@@ -957,7 +956,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         let infcx = self.mc.infcx;
         let delegate = &mut self.delegate;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
-            if let PatKind::Binding(bmode, ..) = pat.node {
+            if let PatKind::Binding(bmode, def_id, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
 
                 // pat_ty: the type of the binding being produced.
@@ -965,8 +964,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
                 // Each match binding is effectively an assignment to the
                 // binding being produced.
-                if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
-                                                    tcx.expect_def(pat.id)) {
+                let def = Def::Local(def_id);
+                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);
                 }
 
@@ -992,9 +991,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         // to the above loop's visit of than the bindings that form
         // the leaves of the pattern tree structure.
         return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
-            match tcx.expect_def_or_none(pat.id) {
-                Some(Def::Variant(variant_did)) |
-                Some(Def::VariantCtor(variant_did, ..)) => {
+            let qpath = match pat.node {
+                PatKind::Path(ref qpath) |
+                PatKind::TupleStruct(ref qpath, ..) |
+                PatKind::Struct(ref qpath, ..) => qpath,
+                _ => return
+            };
+            let def = tcx.tables().qpath_def(qpath, pat.id);
+            match def {
+                Def::Variant(variant_did) |
+                Def::VariantCtor(variant_did, ..) => {
                     let enum_did = tcx.parent_def_id(variant_did).unwrap();
                     let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() {
                         cmt_pat
@@ -1006,14 +1012,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
                     delegate.matched_pat(pat, downcast_cmt, match_mode);
                 }
-                Some(Def::Struct(..)) | Some(Def::StructCtor(..)) | Some(Def::Union(..)) |
-                Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) | Some(Def::SelfTy(..)) => {
+                Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
+                Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => {
                     debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
                     delegate.matched_pat(pat, cmt_pat, match_mode);
                 }
-                None | Some(Def::Local(..)) |
-                Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}
-                def => bug!("unexpected definition: {:?}", def)
+                _ => {}
             }
         }));
     }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index c610c6f75b0..0014d17abb7 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -160,11 +160,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
 
 impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
-        let def = match expr.node {
-            hir::ExprPath(_) => {
-                self.infcx.tcx.expect_def(expr.id)
-            }
-            _ => Def::Err
+        let def = if let hir::ExprPath(ref qpath) = expr.node {
+            self.infcx.tcx.tables().qpath_def(qpath, expr.id)
+        } else {
+            Def::Err
         };
         match def {
             Def::Fn(did) if self.def_id_is_transmute(did) => {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index eefed0a5a74..eb00238492e 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -111,7 +111,6 @@ use self::VarKind::*;
 
 use dep_graph::DepNode;
 use hir::def::*;
-use hir::pat_util;
 use ty::{self, TyCtxt, ParameterEnvironment};
 use traits::{self, Reveal};
 use ty::subst::Subst;
@@ -379,7 +378,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(&arg.pat, |_bm, arg_id, _x, path1| {
+        arg.pat.each_binding(|_bm, arg_id, _x, path1| {
             debug!("adding argument {}", arg_id);
             let name = path1.node;
             fn_maps.add_variable(Arg(arg_id, name));
@@ -412,7 +411,7 @@ fn visit_fn(ir: &mut IrMaps,
 }
 
 fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
-    pat_util::pat_bindings(&local.pat, |_, p_id, sp, path1| {
+    local.pat.each_binding(|_, p_id, sp, path1| {
         debug!("adding local variable {}", p_id);
         let name = path1.node;
         ir.add_live_node_for_node(p_id, VarDefNode(sp));
@@ -426,7 +425,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(&pat, |bm, p_id, sp, path1| {
+        pat.each_binding(|bm, p_id, sp, path1| {
             debug!("adding local variable {} from match with bm {:?}",
                    p_id, bm);
             let name = path1.node;
@@ -443,10 +442,9 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
 fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
-      hir::ExprPath(_) => {
-        let def = ir.tcx.expect_def(expr.id);
-        debug!("expr {}: path that leads to {:?}", expr.id, def);
-        if let Def::Local(..) = def {
+      hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+        debug!("expr {}: path that leads to {:?}", expr.id, path.def);
+        if let Def::Local(..) = path.def {
             ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         }
         intravisit::walk_expr(ir, expr);
@@ -495,7 +493,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprInlineAsm(..) | hir::ExprBox(..) |
-      hir::ExprType(..) => {
+      hir::ExprType(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => {
           intravisit::walk_expr(ir, expr);
       }
     }
@@ -587,7 +585,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(pat, |_bm, p_id, sp, _n| {
+        pat.each_binding(|_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);
@@ -684,22 +682,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     }
 
     fn find_loop_scope(&self,
-                       opt_label: Option<ast::Name>,
-                       id: NodeId,
+                       opt_label: Option<hir::Label>,
                        sp: Span)
                        -> NodeId {
         match opt_label {
-            Some(_) => {
-                // Refers to a labeled loop. Use the results of resolve
-                // to find with one
-                match self.ir.tcx.expect_def(id) {
-                    Def::Label(loop_id) => loop_id,
-                    _ => span_bug!(sp, "label on break/loop \
-                                        doesn't refer to a loop")
-                }
-            }
+            Some(label) => label.loop_id,
             None => {
-                // Vanilla 'break' or 'loop', so use the enclosing
+                // Vanilla 'break' or 'continue', so use the enclosing
                 // loop scope
                 if self.loop_scope.is_empty() {
                     span_bug!(sp, "break outside loop");
@@ -922,8 +911,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         match expr.node {
           // Interesting cases with control flow or which gen/kill
 
-          hir::ExprPath(hir::QPath::Resolved(..)) => {
-              self.access_path(expr, succ, ACC_READ | ACC_USE)
+          hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+              self.access_path(expr.id, path, succ, ACC_READ | ACC_USE)
           }
 
           hir::ExprField(ref e, _) => {
@@ -1037,7 +1026,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprBreak(opt_label, ref opt_expr) => {
               // Find which label this break jumps to
-              let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
+              let sc = self.find_loop_scope(opt_label, expr.span);
 
               // Now that we know the label we're going to,
               // look it up in the break loop nodes table
@@ -1050,7 +1039,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprAgain(opt_label) => {
               // Find which label this expr continues to
-              let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
+              let sc = self.find_loop_scope(opt_label, expr.span);
 
               // Now that we know the label we're going to,
               // look it up in the continue loop nodes table
@@ -1246,8 +1235,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                     -> LiveNode {
         match expr.node {
-          hir::ExprPath(hir::QPath::Resolved(..)) => {
-              self.access_path(expr, succ, acc)
+          hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+              self.access_path(expr.id, path, succ, acc)
           }
 
           // We do not track other lvalues, so just propagate through
@@ -1258,15 +1247,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
+    fn access_path(&mut self, id: NodeId, path: &hir::Path, succ: LiveNode, acc: u32)
                    -> LiveNode {
-        match self.ir.tcx.expect_def(expr.id) {
+        match path.def {
           Def::Local(def_id) => {
             let nid = self.ir.tcx.map.as_local_node_id(def_id).unwrap();
-            let ln = self.live_node(expr.id, expr.span);
+            let ln = self.live_node(id, path.span);
             if acc != 0 {
                 self.init_from_succ(ln, succ);
-                let var = self.variable(nid, expr.span);
+                let var = self.variable(nid, path.span);
                 self.acc(ln, var, acc);
             }
             ln
@@ -1482,8 +1471,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
-            hir::ExprPath(hir::QPath::Resolved(..)) => {
-                if let Def::Local(def_id) = self.ir.tcx.expect_def(expr.id) {
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                if let Def::Local(def_id) = path.def {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
                     // mutable, then check for a reassignment to flag the mutability
@@ -1513,7 +1502,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(&arg.pat, |_bm, p_id, sp, path1| {
+            arg.pat.each_binding(|_bm, p_id, sp, path1| {
                 let var = self.variable(p_id, sp);
                 // Ignore unused self.
                 let name = path1.node;
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 1ca078dcd2e..b9542d6fc5c 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -488,8 +488,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          hir::ExprPath(_) => {
-            self.cat_def(expr.id, expr.span, expr_ty, self.tcx().expect_def(expr.id))
+          hir::ExprPath(ref qpath) => {
+            let def = self.tcx().tables().qpath_def(qpath, expr.id);
+            self.cat_def(expr.id, expr.span, expr_ty, def)
           }
 
           hir::ExprType(ref e, _) => {
@@ -1062,24 +1063,32 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         // Note: This goes up here (rather than within the PatKind::TupleStruct arm
         // alone) because PatKind::Struct can also refer to variants.
-        let cmt = match self.tcx().expect_def_or_none(pat.id) {
-            Some(Def::Err) => return Err(()),
-            Some(Def::Variant(variant_did)) |
-            Some(Def::VariantCtor(variant_did, ..)) => {
-                // univariant enums do not need downcasts
-                let enum_did = self.tcx().parent_def_id(variant_did).unwrap();
-                if !self.tcx().lookup_adt_def(enum_did).is_univariant() {
-                    self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
-                } else {
-                    cmt
+        let cmt = match pat.node {
+            PatKind::Path(hir::QPath::Resolved(_, ref path)) |
+            PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
+            PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
+                match path.def {
+                    Def::Err => return Err(()),
+                    Def::Variant(variant_did) |
+                    Def::VariantCtor(variant_did, ..) => {
+                        // univariant enums do not need downcasts
+                        let enum_did = self.tcx().parent_def_id(variant_did).unwrap();
+                        if !self.tcx().lookup_adt_def(enum_did).is_univariant() {
+                            self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
+                        } else {
+                            cmt
+                        }
+                    }
+                    _ => cmt
                 }
             }
             _ => cmt
         };
 
         match pat.node {
-          PatKind::TupleStruct(_, ref subpats, ddpos) => {
-            let expected_len = match self.tcx().expect_def(pat.id) {
+          PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
+            let def = self.tcx().tables().qpath_def(qpath, pat.id);
+            let expected_len = match def {
                 Def::VariantCtor(def_id, CtorKind::Fn) => {
                     let enum_def = self.tcx().parent_def_id(def_id).unwrap();
                     self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len()
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 91c1c63d890..e9b731ebaf2 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -90,45 +90,40 @@ struct ReachableContext<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
-        match expr.node {
-            hir::ExprPath(_) => {
-                let def = self.tcx.expect_def(expr.id);
-                let def_id = def.def_id();
-                if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
-                    if self.def_id_represents_local_inlined_item(def_id) {
-                        self.worklist.push(node_id);
-                    } else {
-                        match def {
-                            // If this path leads to a constant, then we need to
-                            // recurse into the constant to continue finding
-                            // items that are reachable.
-                            Def::Const(..) | Def::AssociatedConst(..) => {
-                                self.worklist.push(node_id);
-                            }
-
-                            // If this wasn't a static, then the destination is
-                            // surely reachable.
-                            _ => {
-                                self.reachable_symbols.insert(node_id);
-                            }
-                        }
-                    }
-                }
+        let def = match expr.node {
+            hir::ExprPath(ref qpath) => {
+                Some(self.tcx.tables().qpath_def(qpath, expr.id))
             }
             hir::ExprMethodCall(..) => {
                 let method_call = ty::MethodCall::expr(expr.id);
-                let def_id = self.tcx.tables().method_map[&method_call].def_id;
+                let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
+                Some(Def::Method(def_id))
+            }
+            _ => None
+        };
+
+        if let Some(def) = def {
+            let def_id = def.def_id();
+            if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+                if self.def_id_represents_local_inlined_item(def_id) {
+                    self.worklist.push(node_id);
+                } else {
+                    match def {
+                        // If this path leads to a constant, then we need to
+                        // recurse into the constant to continue finding
+                        // items that are reachable.
+                        Def::Const(..) | Def::AssociatedConst(..) => {
+                            self.worklist.push(node_id);
+                        }
 
-                // Mark the trait item (and, possibly, its default impl) as reachable
-                // Or mark inherent impl item as reachable
-                if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
-                    if self.def_id_represents_local_inlined_item(def_id) {
-                        self.worklist.push(node_id)
+                        // If this wasn't a static, then the destination is
+                        // surely reachable.
+                        _ => {
+                            self.reachable_symbols.insert(node_id);
+                        }
                     }
-                    self.reachable_symbols.insert(node_id);
                 }
             }
-            _ => {}
         }
 
         intravisit::walk_expr(self, expr)
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index f256d6d9b4f..d07062f98a9 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -21,7 +21,7 @@ use self::ScopeChain::*;
 use dep_graph::DepNode;
 use hir::map::Map;
 use session::Session;
-use hir::def::{Def, DefMap};
+use hir::def::Def;
 use hir::def_id::DefId;
 use middle::region;
 use ty;
@@ -65,7 +65,6 @@ struct LifetimeContext<'a, 'tcx: 'a> {
     hir_map: &'a Map<'tcx>,
     map: &'a mut NamedRegionMap,
     scope: Scope<'a>,
-    def_map: &'a DefMap,
     // Deep breath. Our representation for poly trait refs contains a single
     // binder and thus we only allow a single level of quantification. However,
     // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
@@ -109,8 +108,7 @@ type Scope<'a> = &'a ScopeChain<'a>;
 static ROOT_SCOPE: ScopeChain<'static> = RootScope;
 
 pub fn krate(sess: &Session,
-             hir_map: &Map,
-             def_map: &DefMap)
+             hir_map: &Map)
              -> Result<NamedRegionMap, usize> {
     let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes);
     let krate = hir_map.krate();
@@ -124,7 +122,6 @@ pub fn krate(sess: &Session,
             hir_map: hir_map,
             map: &mut map,
             scope: &ROOT_SCOPE,
-            def_map: def_map,
             trait_ref_hack: false,
             labels_in_fn: vec![],
         }, krate);
@@ -247,8 +244,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
                 // if this path references a trait, then this will resolve to
                 // a trait ref, which introduces a binding scope.
-                match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) {
-                    Some((Def::Trait(..), 0)) => {
+                match path.def {
+                    Def::Trait(..) => {
                         self.with(LateScope(&[], self.scope), |_, this| {
                             this.visit_path(path, ty.id);
                         });
@@ -541,7 +538,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             hir_map: hir_map,
             map: *map,
             scope: &wrap_scope,
-            def_map: self.def_map,
             trait_ref_hack: self.trait_ref_hack,
             labels_in_fn: self.labels_in_fn.clone(),
         };
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index d7a29e190a8..29af505f9dc 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -468,8 +468,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         intravisit::walk_expr(self, ex);
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
-        check_path(self.tcx, path, id,
+    fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
+        check_path(self.tcx, path,
                    &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
         intravisit::walk_path(self, path)
     }
@@ -526,7 +526,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // individually as it's possible to have a stable trait with unstable
         // items.
         hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => {
-            let trait_did = tcx.expect_def(t.ref_id).def_id();
+            let trait_did = t.path.def.def_id();
             for impl_item_ref in impl_item_refs {
                 let impl_item = tcx.map.impl_item(impl_item_ref.id);
                 let item = tcx.associated_items(trait_did)
@@ -553,9 +553,9 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
             let method_call = ty::MethodCall::expr(e.id);
             tcx.tables().method_map[&method_call].def_id
         }
-        hir::ExprPath(hir::QPath::TypeRelative(..)) => {
+        hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
             span = e.span;
-            tcx.expect_def(e.id).def_id()
+            tcx.tables().qpath_def(qpath, e.id).def_id()
         }
         hir::ExprField(ref base_e, ref field) => {
             span = field.span;
@@ -611,14 +611,13 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
 }
 
 pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            path: &hir::Path, id: ast::NodeId,
+                            path: &hir::Path,
                             cb: &mut FnMut(DefId, Span,
                                            &Option<&Stability>,
                                            &Option<DeprecationEntry>)) {
-    // Paths in import prefixes may have no resolution.
-    match tcx.expect_def_or_none(id) {
-        None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => {}
-        Some(def) => maybe_do_stability_check(tcx, def.def_id(), path.span, cb)
+    match path.def {
+        Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {}
+        _ => maybe_do_stability_check(tcx, path.def.def_id(), path.span, cb)
     }
 }
 
@@ -629,8 +628,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
     debug!("check_pat(pat = {:?})", pat);
     if is_internal(tcx, pat.span) { return; }
 
-    if let PatKind::Path(hir::QPath::TypeRelative(..)) = pat.node {
-        let def_id = tcx.expect_def(pat.id).def_id();
+    if let PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) = pat.node {
+        let def_id = tcx.tables().qpath_def(qpath, pat.id).def_id();
         maybe_do_stability_check(tcx, def_id, pat.span, cb)
     }
 
@@ -665,7 +664,7 @@ pub fn check_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: &hir::Ty,
     if is_internal(tcx, ty.span) { return; }
 
     if let hir::TyPath(hir::QPath::TypeRelative(..)) = ty.node {
-        let def_id = tcx.expect_def(ty.id).def_id();
+        let def_id = tcx.tables().type_relative_path_defs[&ty.id].def_id();
         maybe_do_stability_check(tcx, def_id, ty.span, cb);
     }
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 20855c46b68..ea81c85ba6a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -14,7 +14,7 @@ use dep_graph::{DepGraph, DepTrackingMap};
 use session::Session;
 use middle;
 use hir::TraitMap;
-use hir::def::DefMap;
+use hir::def::Def;
 use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
 use hir::map as ast_map;
 use hir::map::{DefKey, DefPathData, DisambiguatedDefPathData};
@@ -201,6 +201,9 @@ pub struct CommonTypes<'tcx> {
 }
 
 pub struct Tables<'tcx> {
+    /// Resolved definitions for `<T>::X` associated paths.
+    pub type_relative_path_defs: NodeMap<Def>,
+
     /// Stores the types for various nodes in the AST.  Note that this table
     /// is not guaranteed to be populated until after typeck.  See
     /// typeck::check::fn_ctxt for details.
@@ -244,6 +247,7 @@ pub struct Tables<'tcx> {
 impl<'a, 'gcx, 'tcx> Tables<'tcx> {
     pub fn empty() -> Tables<'tcx> {
         Tables {
+            type_relative_path_defs: NodeMap(),
             node_types: FxHashMap(),
             item_substs: NodeMap(),
             adjustments: NodeMap(),
@@ -256,6 +260,16 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> {
         }
     }
 
+    /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
+    pub fn qpath_def(&self, qpath: &hir::QPath, id: NodeId) -> Def {
+        match *qpath {
+            hir::QPath::Resolved(_, ref path) => path.def,
+            hir::QPath::TypeRelative(..) => {
+                self.type_relative_path_defs.get(&id).cloned().unwrap_or(Def::Err)
+            }
+        }
+    }
+
     pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> {
         match self.node_id_to_type_opt(id) {
             Some(ty) => ty,
@@ -379,11 +393,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub sess: &'tcx Session,
 
-    /// Map from path id to the results from resolve; generated
-    /// initially by resolve and updated during typeck in some cases
-    /// (e.g., UFCS paths)
-    pub def_map: RefCell<DefMap>,
-
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: TraitMap,
@@ -768,7 +777,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// reference to the context, to allow formatting values that need it.
     pub fn create_and_enter<F, R>(s: &'tcx Session,
                                   arenas: &'tcx CtxtArenas<'tcx>,
-                                  def_map: DefMap,
                                   trait_map: TraitMap,
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   map: ast_map::Map<'tcx>,
@@ -797,7 +805,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
             variance_computed: Cell::new(false),
             sess: s,
-            def_map: RefCell::new(def_map),
             trait_map: trait_map,
             tables: RefCell::new(Tables::empty()),
             impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3d02ff4651f..ee7cf0788e5 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,7 +19,7 @@ pub use self::fold::TypeFoldable;
 use dep_graph::{self, DepNode};
 use hir::map as ast_map;
 use middle;
-use hir::def::{Def, CtorKind, PathResolution, ExportMap};
+use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
@@ -247,7 +247,7 @@ impl Visibility {
         match *visibility {
             hir::Public => Visibility::Public,
             hir::Visibility::Crate => Visibility::Restricted(ast::CRATE_NODE_ID),
-            hir::Visibility::Restricted { id, .. } => match tcx.expect_def(id) {
+            hir::Visibility::Restricted { ref path, .. } => match path.def {
                 // If there is no resolution, `resolve` will have already reported an error, so
                 // assume that the visibility is public to avoid reporting more privacy errors.
                 Def::Err => Visibility::Public,
@@ -2047,7 +2047,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         match self.map.find(id) {
             Some(ast_map::NodeLocal(pat)) => {
                 match pat.node {
-                    hir::PatKind::Binding(_, ref path1, _) => path1.node.as_str(),
+                    hir::PatKind::Binding(_, _, ref path1, _) => path1.node.as_str(),
                     _ => {
                         bug!("Variable id {} maps to {:?}, not local", id, pat);
                     },
@@ -2059,8 +2059,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn expr_is_lval(self, expr: &hir::Expr) -> bool {
          match expr.node {
-            hir::ExprPath(hir::QPath::Resolved(..)) => {
-                match self.expect_def(expr.id) {
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                match path.def {
                     Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
                     _ => false,
                 }
@@ -2298,22 +2298,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             || self.sess.cstore.impl_trait_ref(self.global_tcx(), id))
     }
 
-    /// Returns a path resolution for node id if it exists, panics otherwise.
-    pub fn expect_resolution(self, id: NodeId) -> PathResolution {
-        *self.def_map.borrow().get(&id).expect("no def-map entry for node id")
-    }
-
-    /// Returns a fully resolved definition for node id if it exists, panics otherwise.
-    pub fn expect_def(self, id: NodeId) -> Def {
-        self.expect_resolution(id).full_def()
-    }
-
-    /// Returns a fully resolved definition for node id if it exists, or none if no
-    /// definition exists, panics on partial resolutions to catch errors.
-    pub fn expect_def_or_none(self, id: NodeId) -> Option<Def> {
-        self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
-    }
-
     // Returns `ty::VariantDef` if `def` refers to a struct,
     // or variant or their constructors, panics otherwise.
     pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 7d3e380a3b5..1dde8106ec6 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -14,7 +14,6 @@ use hir::def_id::DefId;
 use hir::map::DefPathData;
 use infer::InferCtxt;
 use hir::map as ast_map;
-use hir::pat_util;
 use traits::{self, Reveal};
 use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::{Disr, ParameterEnvironment};
@@ -180,14 +179,6 @@ 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(pat)
-    }
-
-    pub fn arm_contains_ref_binding(self, arm: &hir::Arm) -> Option<hir::Mutability> {
-        pat_util::arm_contains_ref_binding(arm)
-    }
-
     pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
             ty::TyAdt(def, substs) => {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 51574868f9b..2c277c04a52 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -98,7 +98,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                       move_pat: &hir::Pat,
                                       cmt: mc::cmt<'tcx>) {
     let pat_span_path_opt = match move_pat.node {
-        PatKind::Binding(_, ref path1, _) => {
+        PatKind::Binding(_, _, ref path1, _) => {
             Some(MoveSpanAndPath{span: move_pat.span,
                                  name: path1.node})
         },
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 4731cea0206..db24ad0fd67 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -23,8 +23,8 @@ use rustc_data_structures::indexed_vec::Idx;
 use pattern::{FieldPattern, Pattern, PatternKind};
 use pattern::{PatternFoldable, PatternFolder};
 
-use rustc::hir::def_id::{DefId};
-use rustc::hir::pat_util::def_to_path;
+use rustc::hir::def::Def;
+use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc::hir;
@@ -324,7 +324,12 @@ impl Witness {
 
                 ty::TyAdt(adt, _) => {
                     let v = ctor.variant_for_adt(adt);
-                    let qpath = hir::QPath::Resolved(None, P(def_to_path(cx.tcx, v.did)));
+                    let qpath = hir::QPath::Resolved(None, P(hir::Path {
+                        span: DUMMY_SP,
+                        global: false,
+                        def: Def::Err,
+                        segments: vec![hir::PathSegment::from_name(v.name)].into(),
+                    }));
                     match v.ctor_kind {
                         CtorKind::Fictive => {
                             let field_pats: hir::HirVec<_> = v.fields.iter()
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 3c94d7d6fd5..b67c2c8ec9c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -19,8 +19,6 @@ use eval::report_const_eval_err;
 
 use rustc::dep_graph::DepNode;
 
-use rustc::hir::pat_util::{pat_bindings, pat_contains_bindings};
-
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
 use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
 use rustc::middle::expr_use_visitor as euv;
@@ -262,26 +260,22 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
 
 fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
     pat.walk(|p| {
-        if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node {
+        if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), _, name, None) = p.node {
             let pat_ty = cx.tcx.tables().pat_ty(p);
             if let ty::TyAdt(edef, _) = pat_ty.sty {
-                if edef.is_enum() {
-                    if let Def::Local(..) = cx.tcx.expect_def(p.id) {
-                        if edef.variants.iter().any(|variant| {
-                            variant.name == name.node && variant.ctor_kind == CtorKind::Const
-                        }) {
-                            let ty_path = cx.tcx.item_path_str(edef.did);
-                            let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
-                                "pattern binding `{}` is named the same as one \
-                                of the variants of the type `{}`",
-                                name.node, ty_path);
-                            help!(err,
-                                "if you meant to match on a variant, \
-                                consider making the path in the pattern qualified: `{}::{}`",
-                                ty_path, name.node);
-                            err.emit();
-                        }
-                    }
+                if edef.is_enum() && edef.variants.iter().any(|variant| {
+                    variant.name == name.node && variant.ctor_kind == CtorKind::Const
+                }) {
+                    let ty_path = cx.tcx.item_path_str(edef.did);
+                    let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
+                        "pattern binding `{}` is named the same as one \
+                         of the variants of the type `{}`",
+                        name.node, ty_path);
+                    help!(err,
+                        "if you meant to match on a variant, \
+                        consider making the path in the pattern qualified: `{}::{}`",
+                        ty_path, name.node);
+                    err.emit();
                 }
             }
         }
@@ -290,13 +284,13 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
 }
 
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
-fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
+fn pat_is_catchall(pat: &Pat) -> bool {
     match pat.node {
         PatKind::Binding(.., None) => true,
-        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, s),
-        PatKind::Ref(ref s, _) => pat_is_catchall(dm, s),
+        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
+        PatKind::Ref(ref s, _) => pat_is_catchall(s),
         PatKind::Tuple(ref v, _) => v.iter().all(|p| {
-            pat_is_catchall(dm, &p)
+            pat_is_catchall(&p)
         }),
         _ => false
     }
@@ -374,7 +368,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             }
             if guard.is_none() {
                 seen.push(v);
-                if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), hir_pat) {
+                if catchall.is_none() && pat_is_catchall(hir_pat) {
                     catchall = Some(pat.span);
                 }
             }
@@ -454,7 +448,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
                                    pats: &[P<Pat>]) {
     let mut by_ref_span = None;
     for pat in pats {
-        pat_bindings(&pat, |bm, _, span, _path| {
+        pat.each_binding(|bm, _, span, _path| {
             if let hir::BindByRef(..) = bm {
                 by_ref_span = Some(span);
             }
@@ -465,7 +459,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
         // 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(&p)) {
+        if sub.map_or(false, |p| p.contains_bindings()) {
             struct_span_err!(cx.tcx.sess, p.span, E0007,
                              "cannot bind by-move with sub-bindings")
                 .span_label(p.span, &format!("binds an already bound by-move value by moving it"))
@@ -486,7 +480,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 
     for pat in pats {
         pat.walk(|p| {
-            if let PatKind::Binding(hir::BindByValue(..), _, ref sub) = p.node {
+            if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
                 let pat_ty = cx.tcx.tables().node_id_to_type(p.id);
                 if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
                     check_move(p, sub.as_ref().map(|p| &**p));
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index e8c05ec1a35..053d3072ddf 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -19,9 +19,8 @@ use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::cstore::InlinedItem;
 use rustc::traits;
-use rustc::hir::def::{Def, CtorKind, PathResolution};
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
-use rustc::hir::pat_util::def_to_path;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::subst::Substs;
@@ -42,7 +41,6 @@ use syntax_pos::{self, Span};
 
 use std::borrow::Cow;
 use std::cmp::Ordering;
-use std::collections::hash_map::Entry::Vacant;
 
 use rustc_const_math::*;
 use rustc_errors::DiagnosticBuilder;
@@ -282,26 +280,34 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 .collect::<Result<_, _>>()?, None),
 
         hir::ExprCall(ref callee, ref args) => {
-            let def = tcx.expect_def(callee.id);
-            if let Vacant(entry) = tcx.def_map.borrow_mut().entry(expr.id) {
-               entry.insert(PathResolution::new(def));
-            }
-            let qpath = match def {
-                Def::StructCtor(def_id, CtorKind::Fn) |
-                Def::VariantCtor(def_id, CtorKind::Fn) => {
-                    hir::QPath::Resolved(None, P(def_to_path(tcx, def_id)))
-                }
-                Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat {
-                    id: expr.id,
-                    node: PatKind::Lit(P(expr.clone())),
-                    span: span,
-                })),
+            let qpath = match callee.node {
+                hir::ExprPath(ref qpath) => qpath,
                 _ => bug!()
             };
-            let pats = args.iter()
-                           .map(|expr| const_expr_to_pat(tcx, &*expr, pat_id, span))
-                           .collect::<Result<_, _>>()?;
-            PatKind::TupleStruct(qpath, pats, None)
+            let def = tcx.tables().qpath_def(qpath, callee.id);
+            let ctor_path = if let hir::QPath::Resolved(_, ref path) = *qpath {
+                match def {
+                    Def::StructCtor(_, CtorKind::Fn) |
+                    Def::VariantCtor(_, CtorKind::Fn) => {
+                        Some(path.clone())
+                    }
+                    _ => None
+                }
+            } else {
+                None
+            };
+            match (def, ctor_path) {
+                (Def::Fn(..), None) | (Def::Method(..), None) => {
+                    PatKind::Lit(P(expr.clone()))
+                }
+                (_, Some(ctor_path)) => {
+                    let pats = args.iter()
+                                   .map(|expr| const_expr_to_pat(tcx, expr, pat_id, span))
+                                   .collect::<Result<_, _>>()?;
+                    PatKind::TupleStruct(hir::QPath::Resolved(None, ctor_path), pats, None)
+                }
+                _ => bug!()
+            }
         }
 
         hir::ExprStruct(ref qpath, ref fields, None) => {
@@ -326,8 +332,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             PatKind::Slice(pats, None, hir::HirVec::new())
         }
 
-        hir::ExprPath(_) => {
-            match tcx.expect_def(expr.id) {
+        hir::ExprPath(ref qpath) => {
+            let def = tcx.tables().qpath_def(qpath, expr.id);
+            match def {
                 Def::StructCtor(_, CtorKind::Const) |
                 Def::VariantCtor(_, CtorKind::Const) => {
                     match expr.node {
@@ -797,13 +804,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
         }
       }
-      hir::ExprPath(_) => {
-          // This function can be used before type checking when not all paths are fully resolved.
-          // FIXME: There's probably a better way to make sure we don't panic here.
-          let def = match tcx.expect_def_or_none(e.id) {
-              Some(def) => def,
-              None => signal!(e, UnresolvedPath)
-          };
+      hir::ExprPath(ref qpath) => {
+          let def = tcx.tables().qpath_def(qpath, e.id);
           match def {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
@@ -854,6 +856,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   }
               },
               Def::Method(id) | Def::Fn(id) => Function(id),
+              Def::Err => signal!(e, UnresolvedPath),
               _ => signal!(e, NonConstPath),
           }
       }
@@ -882,8 +885,9 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   fn_args
               )?;
               debug!("const call arg: {:?}", arg);
-              let old = call_args.insert(tcx.expect_def(arg.pat.id).def_id(), arg_val);
-              assert!(old.is_none());
+              if let PatKind::Binding(_, def_id, _, _) = arg.pat.node {
+                assert!(call_args.insert(def_id, arg_val).is_none());
+              }
           }
           debug!("const call({:?})", call_args);
           eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
@@ -1368,10 +1372,8 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 tcx, &err, count_expr.span, reason);
 
             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
-                if !path.global && path.segments.len() == 1 {
-                    if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) {
-                        diag.note(&format!("`{}` is a variable", path.segments[0].name));
-                    }
+                if let Def::Local(..) = path.def {
+                    diag.note(&format!("`{}` is a variable", path));
                 }
             }
 
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 241920f2949..8e803da98f8 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -163,8 +163,9 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatKind::Path(..) => {
-                match self.tcx.expect_def(pat.id) {
+            PatKind::Path(ref qpath) => {
+                let def = self.tcx.tables().qpath_def(qpath, pat.id);
+                match def {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                         let tcx = self.tcx.global_tcx();
                         let substs = tcx.tables().node_id_item_substs(pat.id)
@@ -188,7 +189,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                             }
                         }
                     }
-                    _ => self.lower_variant_or_leaf(pat, vec![])
+                    _ => self.lower_variant_or_leaf(def, vec![])
                 }
             }
 
@@ -242,8 +243,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatKind::Binding(bm, ref ident, ref sub) => {
-                let def_id = self.tcx.expect_def(pat.id).def_id();
+            PatKind::Binding(bm, def_id, ref ident, ref sub) => {
                 let id = self.tcx.map.as_local_node_id(def_id).unwrap();
                 let var_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let region = match var_ty.sty {
@@ -281,13 +281,14 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
+            PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => {
+                let def = self.tcx.tables().qpath_def(qpath, pat.id);
                 let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
                 };
-                let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
+                let variant_def = adt_def.variant_of_def(def);
 
                 let subpatterns =
                         subpatterns.iter()
@@ -297,10 +298,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                                        pattern: self.lower_pattern(field),
                                    })
                                    .collect();
-                self.lower_variant_or_leaf(pat, subpatterns)
+                self.lower_variant_or_leaf(def, subpatterns)
             }
 
-            PatKind::Struct(_, ref fields, _) => {
+            PatKind::Struct(ref qpath, ref fields, _) => {
+                let def = self.tcx.tables().qpath_def(qpath, pat.id);
                 let pat_ty = self.tcx.tables().node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
@@ -310,7 +312,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                             "struct pattern not applied to an ADT");
                     }
                 };
-                let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
+                let variant_def = adt_def.variant_of_def(def);
 
                 let subpatterns =
                     fields.iter()
@@ -329,7 +331,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                           })
                           .collect();
 
-                self.lower_variant_or_leaf(pat, subpatterns)
+                self.lower_variant_or_leaf(def, subpatterns)
             }
         };
 
@@ -418,11 +420,11 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
 
     fn lower_variant_or_leaf(
         &mut self,
-        pat: &hir::Pat,
+        def: Def,
         subpatterns: Vec<FieldPattern<'tcx>>)
         -> PatternKind<'tcx>
     {
-        match self.tcx.expect_def(pat.id) {
+        match def {
             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
                 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
                 let adt_def = self.tcx.lookup_adt_def(enum_id);
@@ -442,9 +444,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 PatternKind::Leaf { subpatterns: subpatterns }
             }
 
-            def => {
-                span_bug!(pat.span, "inappropriate def for pattern: {:?}", def);
-            }
+            _ => bug!()
         }
     }
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9a4ecef0c0e..a1d1d110527 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -840,9 +840,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     let named_region_map = time(time_passes,
                                 "lifetime resolution",
-                                || middle::resolve_lifetime::krate(sess,
-                                                                   &hir_map,
-                                                                   &resolutions.def_map))?;
+                                || middle::resolve_lifetime::krate(sess, &hir_map))?;
 
     time(time_passes,
          "looking for entry point",
@@ -859,17 +857,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     time(time_passes,
          "loop checking",
-         || loops::check_crate(sess, &resolutions.def_map, &hir_map));
+         || loops::check_crate(sess, &hir_map));
 
     time(time_passes,
               "static item recursion checking",
-              || static_recursion::check_crate(sess, &resolutions.def_map, &hir_map))?;
+              || static_recursion::check_crate(sess, &hir_map))?;
 
     let index = stability::Index::new(&hir_map);
 
     TyCtxt::create_and_enter(sess,
                              arenas,
-                             resolutions.def_map,
                              resolutions.trait_map,
                              named_region_map,
                              hir_map,
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index a4f0e290384..464e15faeaf 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -131,12 +131,11 @@ fn test_env<F>(source_string: &str,
 
     // run just enough stuff to build a tcx:
     let lang_items = lang_items::collect_language_items(&sess, &ast_map);
-    let named_region_map = resolve_lifetime::krate(&sess, &ast_map, &resolutions.def_map);
+    let named_region_map = resolve_lifetime::krate(&sess, &ast_map);
     let region_map = region::resolve_crate(&sess, &ast_map);
     let index = stability::Index::new(&ast_map);
     TyCtxt::create_and_enter(&sess,
                              &arenas,
-                             resolutions.def_map,
                              resolutions.trait_map,
                              named_region_map.unwrap(),
                              ast_map,
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 8c6d8dffa1d..e2b141f2ea6 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -23,7 +23,7 @@ use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
 use syntax::tokenstream;
 use rustc::hir;
 use rustc::hir::*;
-use rustc::hir::def::{Def, PathResolution};
+use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit as visit;
 use rustc::ty::TyCtxt;
@@ -335,8 +335,8 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprIndex(..)            => (SawExprIndex, true),
         ExprPath(_)              => (SawExprPath, false),
         ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(id, _)         => (SawExprBreak(id.map(|id| id.node.as_str())), false),
-        ExprAgain(id)            => (SawExprAgain(id.map(|id| id.node.as_str())), false),
+        ExprBreak(label, _)      => (SawExprBreak(label.map(|l| l.name.as_str())), false),
+        ExprAgain(label)         => (SawExprAgain(label.map(|l| l.name.as_str())), false),
         ExprRet(..)              => (SawExprRet, false),
         ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(a), false),
         ExprStruct(..)           => (SawExprStruct, false),
@@ -669,6 +669,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         visit::walk_path(self, path)
     }
 
+    fn visit_def_mention(&mut self, def: Def) {
+        self.hash_def(def);
+    }
+
     fn visit_block(&mut self, b: &'tcx Block) {
         debug!("visit_block: st={:?}", self.st);
         SawBlock.hash(self.st);
@@ -799,11 +803,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
         // or not an entry was present (we are already hashing what
         // variant it is above when we visit the HIR).
 
-        if let Some(def) = self.tcx.def_map.borrow().get(&id) {
-            debug!("hash_resolve: id={:?} def={:?} st={:?}", id, def, self.st);
-            self.hash_partial_def(def);
-        }
-
         if let Some(traits) = self.tcx.trait_map.get(&id) {
             debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
             traits.len().hash(self.st);
@@ -825,11 +824,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
         self.compute_def_id_hash(def_id).hash(self.st);
     }
 
-    fn hash_partial_def(&mut self, def: &PathResolution) {
-        self.hash_def(def.base_def);
-        def.depth.hash(self.st);
-    }
-
     fn hash_def(&mut self, def: Def) {
         match def {
             // Crucial point: for all of these variants, the variant +
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 25ea3d65993..7c3ea656124 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -288,12 +288,17 @@ impl LateLintPass for NonSnakeCase {
     }
 
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
-        if let &PatKind::Binding(_, ref path1, _) = &p.node {
-            // Exclude parameter names from foreign functions (they have no `Def`)
-            if cx.tcx.expect_def_or_none(p.id).is_some() {
-                self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
+        // Exclude parameter names from foreign functions
+        let parent_node = cx.tcx.map.get_parent_node(p.id);
+        if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
+            if let hir::ForeignItemFn(..) = item.node {
+                return;
             }
         }
+
+        if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
+            self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
+        }
     }
 
     fn check_struct_def(&mut self,
@@ -378,7 +383,7 @@ impl LateLintPass for NonUpperCaseGlobals {
         // Lint for constants that look like binding identifiers (#7526)
         if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
             if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
-                if let Def::Const(..) = cx.tcx.expect_def(p.id) {
+                if let Def::Const(..) = path.def {
                     NonUpperCaseGlobals::check_upper_case(cx,
                                                           "constant in pattern",
                                                           path.segments[0].name,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index d91327bc86b..490b0028d74 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -167,7 +167,7 @@ impl LateLintPass for NonShorthandFieldPatterns {
                 if fieldpat.node.is_shorthand {
                     continue;
                 }
-                if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
+                if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node {
                     if ident.node == fieldpat.node.name {
                         cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
                                      fieldpat.span,
@@ -391,7 +391,7 @@ impl LateLintPass for MissingDoc {
             hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
-                let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
+                let real_trait = trait_ref.path.def.def_id();
                 if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
                     match cx.tcx.map.find(node_id) {
                         Some(hir_map::NodeItem(item)) => {
@@ -697,10 +697,9 @@ impl LateLintPass for Deprecated {
                               &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
-    fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
+    fn check_path(&mut self, cx: &LateContext, path: &hir::Path, _: ast::NodeId) {
         stability::check_path(cx.tcx,
                               path,
-                              id,
                               &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
@@ -926,8 +925,12 @@ impl LateLintPass for UnconditionalRecursion {
         fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    tcx.expect_def_or_none(callee.id)
-                        .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id))
+                    let def = if let hir::ExprPath(ref qpath) = callee.node {
+                        tcx.tables().qpath_def(qpath, callee.id)
+                    } else {
+                        return false;
+                    };
+                    def.def_id() == tcx.map.local_def_id(fn_id)
                 }
                 _ => false,
             }
@@ -965,10 +968,13 @@ impl LateLintPass for UnconditionalRecursion {
             // Check for calls to methods via explicit paths (e.g. `T::method()`).
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    // The callee is an arbitrary expression,
-                    // it doesn't necessarily have a definition.
-                    match tcx.expect_def_or_none(callee.id) {
-                        Some(Def::Method(def_id)) => {
+                    let def = if let hir::ExprPath(ref qpath) = callee.node {
+                        tcx.tables().qpath_def(qpath, callee.id)
+                    } else {
+                        return false;
+                    };
+                    match def {
+                        Def::Method(def_id) => {
                             let substs = tcx.tables().node_id_item_substs(callee.id)
                                 .unwrap_or_else(|| tcx.intern_substs(&[]));
                             method_call_refers_to_method(
@@ -1201,11 +1207,12 @@ impl LateLintPass for MutableTransmutes {
             (cx: &LateContext<'a, 'tcx>,
              expr: &hir::Expr)
              -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
-            match expr.node {
-                hir::ExprPath(_) => (),
-                _ => return None,
-            }
-            if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
+            let def = if let hir::ExprPath(ref qpath) = expr.node {
+                cx.tcx.tables().qpath_def(qpath, expr.id)
+            } else {
+                return None;
+            };
+            if let Def::Fn(did) = def {
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 324cbd17ab3..873c141065e 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir::pat_util;
 use rustc::ty;
 use rustc::ty::adjustment;
 use util::nodemap::FxHashMap;
@@ -44,7 +43,7 @@ impl UnusedMut {
 
         let mut mutables = FxHashMap();
         for p in pats {
-            pat_util::pat_bindings(p, |mode, id, _, path1| {
+            p.each_binding(|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_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index e2fa535bb44..806d20c72dc 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -18,7 +18,7 @@ use schema::*;
 
 use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
 use rustc::middle::const_qualif::ConstQualif;
-use rustc::hir::def::{self, Def};
+use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, TyCtxt, Ty};
 
@@ -35,7 +35,7 @@ pub struct Ast<'tcx> {
 
 #[derive(RustcEncodable, RustcDecodable)]
 enum TableEntry<'tcx> {
-    Def(Def),
+    TypeRelativeDef(Def),
     NodeType(Ty<'tcx>),
     ItemSubsts(ty::ItemSubsts<'tcx>),
     Adjustment(ty::adjustment::Adjustment<'tcx>),
@@ -93,7 +93,8 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx>
             }
         };
 
-        encode(tcx.expect_def_or_none(id).map(TableEntry::Def));
+        encode(tcx.tables().type_relative_path_defs.get(&id).cloned()
+                  .map(TableEntry::TypeRelativeDef));
         encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
         encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
         encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
@@ -140,8 +141,8 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
 
     for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
         match entry {
-            TableEntry::Def(def) => {
-                tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def));
+            TableEntry::TypeRelativeDef(def) => {
+                tcx.tables.borrow_mut().type_relative_path_defs.insert(id, def);
             }
             TableEntry::NodeType(ty) => {
                 tcx.tables.borrow_mut().node_types.insert(id, ty);
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 8f3e8a48b1a..a243962b4ee 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -597,7 +597,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
         self.lazy_seq(decl.inputs.iter().map(|arg| {
-            if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
+            if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
                 path1.node
             } else {
                 Symbol::intern("")
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 5713ee45b9d..0e4dbb04777 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -182,7 +182,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                 by_ref: by_ref
             };
             if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(var_id) {
-                if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
+                if let hir::PatKind::Binding(_, _, ref ident, _) = pat.node {
                     decl.debug_name = ident.node;
                 }
             }
@@ -286,7 +286,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // If this is a simple binding pattern, give the local a nice name for debuginfo.
             let mut name = None;
             if let Some(pat) = pattern {
-                if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
+                if let hir::PatKind::Binding(_, _, ref ident, _) = pat.node {
                     name = Some(ident.node);
                 }
             }
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0c796ad42bb..a148ae08c53 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -18,7 +18,6 @@ use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
 use rustc_const_eval as const_eval;
-use rustc::middle::region::CodeExtent;
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -265,10 +264,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     args: vec![fun.to_ref(), tupled_args.to_ref()]
                 }
             } else {
-                let adt_data = if let hir::ExprPath(hir::QPath::Resolved(..)) = fun.node {
+                let adt_data = if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = fun.node {
                     // Tuple-like ADTs are represented as ExprCall. We convert them here.
                     expr_ty.ty_adt_def().and_then(|adt_def|{
-                        match cx.tcx.expect_def(fun.id) {
+                        match path.def {
                             Def::VariantCtor(variant_id, CtorKind::Fn) => {
                                 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
                             },
@@ -456,7 +455,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprStruct(_, ref fields, ref base) => {
+        hir::ExprStruct(ref qpath, ref fields, ref base) => {
             match expr_ty.sty {
                 ty::TyAdt(adt, substs) => match adt.adt_kind() {
                     AdtKind::Struct | AdtKind::Union => {
@@ -476,7 +475,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         }
                     }
                     AdtKind::Enum => {
-                        match cx.tcx.expect_def(expr.id) {
+                        let def = match *qpath {
+                            hir::QPath::Resolved(_, ref path) => path.def,
+                            hir::QPath::TypeRelative(..) => Def::Err
+                        };
+                        match def {
                             Def::Variant(variant_id) => {
                                 assert!(base.is_none());
 
@@ -490,7 +493,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                     base: None
                                 }
                             }
-                            ref def => {
+                            _ => {
                                 span_bug!(
                                     expr.span,
                                     "unexpected def: {:?}",
@@ -531,8 +534,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprPath(_) => {
-            convert_path_expr(cx, expr)
+        hir::ExprPath(ref qpath) => {
+            let def = cx.tcx.tables().qpath_def(qpath, expr.id);
+            convert_path_expr(cx, expr, def)
         }
 
         hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
@@ -559,10 +563,18 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRet(ref v) =>
             ExprKind::Return { value: v.to_ref() },
         hir::ExprBreak(label, ref value) =>
-            ExprKind::Break { label: label.map(|_| loop_label(cx, expr)),
-                              value: value.to_ref() },
+            ExprKind::Break {
+                label: label.map(|label| {
+                    cx.tcx.region_maps.node_extent(label.loop_id)
+                }),
+                value: value.to_ref()
+            },
         hir::ExprAgain(label) =>
-            ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) },
+            ExprKind::Continue {
+                label: label.map(|label| {
+                    cx.tcx.region_maps.node_extent(label.loop_id)
+                })
+            },
         hir::ExprMatch(ref discr, ref arms, _) =>
             ExprKind::Match { discriminant: discr.to_ref(),
                               arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
@@ -661,11 +673,11 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 }
 
 fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                                     expr: &'tcx hir::Expr)
+                                     expr: &'tcx hir::Expr,
+                                     def: Def)
                                      -> ExprKind<'tcx> {
     let substs = cx.tcx.tables().node_id_item_substs(expr.id)
         .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
-    let def = cx.tcx.expect_def(expr.id);
     let def_id = match def {
         // A regular function, constructor function or a constant.
         Def::Fn(def_id) | Def::Method(def_id) |
@@ -990,14 +1002,6 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn loop_label<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                              expr: &'tcx hir::Expr) -> CodeExtent {
-    match cx.tcx.expect_def(expr.id) {
-        Def::Label(loop_id) => cx.tcx.region_maps.node_extent(loop_id),
-        d => span_bug!(expr.span, "loop scope resolved to {:?}", d),
-    }
-}
-
 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
 fn field_refs<'tcx>(variant: VariantDef<'tcx>,
                     fields: &'tcx [hir::Field])
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index ff46273a997..d9b1f247c72 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -487,8 +487,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                 _ => {}
             }
         }
-        hir::ExprPath(_) => {
-            match v.tcx.expect_def(e.id) {
+        hir::ExprPath(ref qpath) => {
+            let def = v.tcx.tables().qpath_def(qpath, e.id);
+            match def {
                 Def::VariantCtor(_, CtorKind::Const) => {
                     // Size is determined by the whole enum, may be non-zero.
                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
@@ -531,17 +532,22 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                 };
             }
             // The callee is an arbitrary expression, it doesn't necessarily have a definition.
-            let is_const = match v.tcx.expect_def_or_none(callee.id) {
-                Some(Def::StructCtor(_, CtorKind::Fn)) |
-                Some(Def::VariantCtor(_, CtorKind::Fn)) => {
+            let def = if let hir::ExprPath(ref qpath) = callee.node {
+                v.tcx.tables().qpath_def(qpath, callee.id)
+            } else {
+                Def::Err
+            };
+            let is_const = match def {
+                Def::StructCtor(_, CtorKind::Fn) |
+                Def::VariantCtor(_, CtorKind::Fn) => {
                     // `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
                     true
                 }
-                Some(Def::Fn(did)) => {
+                Def::Fn(did) => {
                     v.handle_const_fn_call(e, did, node_ty)
                 }
-                Some(Def::Method(did)) => {
+                Def::Method(did) => {
                     match v.tcx.associated_item(did).container {
                         ty::ImplContainer(_) => {
                             v.handle_const_fn_call(e, did, node_ty)
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index c909e75afc1..a622a3faf70 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -12,10 +12,10 @@ use self::Context::*;
 use rustc::session::Session;
 
 use rustc::dep_graph::DepNode;
-use rustc::hir::def::{Def, DefMap};
 use rustc::hir::map::Map;
 use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir;
+use syntax::ast;
 use syntax_pos::Span;
 
 #[derive(Clone, Copy, PartialEq)]
@@ -45,17 +45,15 @@ enum Context {
 #[derive(Copy, Clone)]
 struct CheckLoopVisitor<'a, 'ast: 'a> {
     sess: &'a Session,
-    def_map: &'a DefMap,
     hir_map: &'a Map<'ast>,
     cx: Context,
 }
 
-pub fn check_crate(sess: &Session, def_map: &DefMap, map: &Map) {
+pub fn check_crate(sess: &Session, map: &Map) {
     let _task = map.dep_graph.in_task(DepNode::CheckLoops);
     let krate = map.krate();
     krate.visit_all_item_likes(&mut CheckLoopVisitor {
         sess: sess,
-        def_map: def_map,
         hir_map: map,
         cx: Normal,
     }.as_deep_visitor());
@@ -84,21 +82,18 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckLoopVisitor<'a, 'ast> {
             hir::ExprClosure(.., ref b, _) => {
                 self.with_context(Closure, |v| v.visit_expr(&b));
             }
-            hir::ExprBreak(ref opt_label, ref opt_expr) => {
+            hir::ExprBreak(label, ref opt_expr) => {
                 if opt_expr.is_some() {
-                    let loop_kind = if opt_label.is_some() {
-                        let loop_def = self.def_map.get(&e.id).unwrap().full_def();
-                        if loop_def == Def::Err {
+                    let loop_kind = if let Some(label) = label {
+                        if label.loop_id == ast::DUMMY_NODE_ID {
                             None
-                        } else if let Def::Label(loop_id) = loop_def {
-                            Some(match self.hir_map.expect_expr(loop_id).node {
+                        } else {
+                            Some(match self.hir_map.expect_expr(label.loop_id).node {
                                 hir::ExprWhile(..) => LoopKind::WhileLoop,
                                 hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
                                 ref r => span_bug!(e.span,
                                                    "break label resolved to a non-loop: {:?}", r),
                             })
-                        } else {
-                            span_bug!(e.span, "break resolved to a non-label")
                         }
                     } else if let Loop(kind) = self.cx {
                         Some(kind)
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index b98cf7e602b..b5daf0284e1 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -14,7 +14,7 @@
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as ast_map;
 use rustc::session::{CompileResult, Session};
-use rustc::hir::def::{Def, CtorKind, DefMap};
+use rustc::hir::def::{Def, CtorKind};
 use rustc::util::nodemap::NodeMap;
 
 use syntax::ast;
@@ -27,7 +27,6 @@ use std::cell::RefCell;
 
 struct CheckCrateVisitor<'a, 'ast: 'a> {
     sess: &'a Session,
-    def_map: &'a DefMap,
     ast_map: &'a ast_map::Map<'ast>,
     // `discriminant_map` is a cache that associates the `NodeId`s of local
     // variant definitions with the discriminant expression that applies to
@@ -88,14 +87,12 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
 }
 
 pub fn check_crate<'ast>(sess: &Session,
-                         def_map: &DefMap,
                          ast_map: &ast_map::Map<'ast>)
                          -> CompileResult {
     let _task = ast_map.dep_graph.in_task(DepNode::CheckStaticRecursion);
 
     let mut visitor = CheckCrateVisitor {
         sess: sess,
-        def_map: def_map,
         ast_map: ast_map,
         discriminant_map: RefCell::new(NodeMap()),
     };
@@ -109,7 +106,6 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
     root_span: &'a Span,
     sess: &'a Session,
     ast_map: &'a ast_map::Map<'ast>,
-    def_map: &'a DefMap,
     discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
     idstack: Vec<ast::NodeId>,
 }
@@ -122,7 +118,6 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
             root_span: span,
             sess: v.sess,
             ast_map: v.ast_map,
-            def_map: v.def_map,
             discriminant_map: &v.discriminant_map,
             idstack: Vec::new(),
         }
@@ -250,11 +245,11 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
 
     fn visit_expr(&mut self, e: &'ast hir::Expr) {
         match e.node {
-            hir::ExprPath(_) => {
-                match self.def_map.get(&e.id).map(|d| d.base_def) {
-                    Some(Def::Static(def_id, _)) |
-                    Some(Def::AssociatedConst(def_id)) |
-                    Some(Def::Const(def_id)) => {
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                match path.def {
+                    Def::Static(def_id, _) |
+                    Def::AssociatedConst(def_id) |
+                    Def::Const(def_id) => {
                         if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
                             match self.ast_map.get(node_id) {
                                 ast_map::NodeItem(item) => self.visit_item(item),
@@ -273,7 +268,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
                     // affect the specific variant used, but we need to check
                     // the whole enum definition to see what expression that
                     // might be (if any).
-                    Some(Def::VariantCtor(variant_id, CtorKind::Const)) => {
+                    Def::VariantCtor(variant_id, CtorKind::Const) => {
                         if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) {
                             let variant = self.ast_map.expect_variant(variant_id);
                             let enum_id = self.ast_map.get_parent(variant_id);
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 55e11caac6d..29bcb73602e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -67,8 +67,12 @@ struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
 
 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
-        if let hir::TyPath(_) = ty.node {
-            match self.tcx.expect_def(ty.id) {
+        if let hir::TyPath(ref qpath) = ty.node {
+            let def = match *qpath {
+                hir::QPath::Resolved(_, ref path) => path.def,
+                hir::QPath::TypeRelative(..) => self.tcx.tables().type_relative_path_defs[&ty.id]
+            };
+            match def {
                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
                     Some(AccessLevel::Public)
                 }
@@ -86,7 +90,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     }
 
     fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
-        let did = self.tcx.expect_def(trait_ref.ref_id).def_id();
+        let did = trait_ref.path.def.def_id();
         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
             self.get(node_id)
         } else {
@@ -328,13 +332,16 @@ impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        let path_segment = match ty.node {
-            hir::TyPath(hir::QPath::Resolved(_, ref path)) => path.segments.last(),
-            hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => Some(&**segment),
+        let def_and_segment = match ty.node {
+            hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
+                Some((path.def, path.segments.last().unwrap()))
+            }
+            hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => {
+                Some((self.ev.tcx.tables().type_relative_path_defs[&ty.id], &**segment))
+            }
             _ => None
         };
-        if let Some(segment) = path_segment {
-            let def = self.ev.tcx.expect_def(ty.id);
+        if let Some((def, segment)) = def_and_segment {
             match def {
                 Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
                 Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => {
@@ -365,7 +372,7 @@ impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
     }
 
     fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
-        let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
+        let def_id = trait_ref.path.def.def_id();
         if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
             let item = self.ev.tcx.map.expect_item(node_id);
             self.ev.update(item.id, Some(AccessLevel::Reachable));
@@ -446,9 +453,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
                 let method = self.tcx.tables().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
-            hir::ExprStruct(_, ref expr_fields, _) => {
+            hir::ExprStruct(ref qpath, ref expr_fields, _) => {
+                let def = self.tcx.tables().qpath_def(qpath, expr.id);
                 let adt = self.tcx.tables().expr_ty(expr).ty_adt_def().unwrap();
-                let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
+                let variant = adt.variant_of_def(def);
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
                 // (i.e. `all_fields - fields`), just check them all,
@@ -466,9 +474,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ExprPath(hir::QPath::Resolved(..)) => {
-                if let def @ Def::StructCtor(_, CtorKind::Fn) = self.tcx.expect_def(expr.id) {
-                    let adt_def = self.tcx.expect_variant_def(def);
+            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
+                if let Def::StructCtor(_, CtorKind::Fn) = path.def {
+                    let adt_def = self.tcx.expect_variant_def(path.def);
                     let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| {
                         !field.vis.is_accessible_from(self.curitem, &self.tcx.map)
                     }).map(|(i, _)| i).collect::<Vec<_>>();
@@ -507,9 +515,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
         if self.in_foreign { return }
 
         match pattern.node {
-            PatKind::Struct(_, ref fields, _) => {
+            PatKind::Struct(ref qpath, ref fields, _) => {
+                let def = self.tcx.tables().qpath_def(qpath, pattern.id);
                 let adt = self.tcx.tables().pat_ty(pattern).ty_adt_def().unwrap();
-                let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id));
+                let variant = adt.variant_of_def(def);
                 for field in fields {
                     self.check_field(field.span, adt, variant.field_named(field.node.name));
                 }
@@ -569,8 +578,8 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
 }
 
 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
-    fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
-        let did = match self.tcx.expect_def(path_id) {
+    fn path_is_private_type(&self, path: &hir::Path) -> bool {
+        let did = match path.def {
             Def::PrimTy(..) | Def::SelfTy(..) => return false,
             def => def.def_id(),
         };
@@ -598,7 +607,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     fn check_ty_param_bound(&mut self,
                             ty_param_bound: &hir::TyParamBound) {
         if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
-            if self.path_is_private_type(trait_ref.trait_ref.ref_id) {
+            if self.path_is_private_type(&trait_ref.trait_ref.path) {
                 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
             }
         }
@@ -611,13 +620,16 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
     fn visit_ty(&mut self, ty: &hir::Ty) {
-        if let hir::TyPath(_) = ty.node {
-            if self.inner.path_is_private_type(ty.id) {
+        if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = ty.node {
+            if self.inner.path_is_private_type(path) {
                 self.contains_private = true;
                 // found what we're looking for so let's stop
                 // working.
                 return
-            } else if self.at_outer_type {
+            }
+        }
+        if let hir::TyPath(_) = ty.node {
+            if self.at_outer_type {
                 self.outer_type_is_public_path = true;
             }
         }
@@ -687,7 +699,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                 let not_private_trait =
                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
                                               |tr| {
-                        let did = self.tcx.expect_def(tr.ref_id).def_id();
+                        let did = tr.path.def.def_id();
 
                         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
                             self.trait_is_public(node_id)
@@ -849,8 +861,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
-        if let hir::TyPath(_) = t.node {
-            if self.path_is_private_type(t.id) {
+        if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = t.node {
+            if self.path_is_private_type(path) {
                 self.old_error_set.insert(t.id);
             }
         }
@@ -941,13 +953,17 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &hir::Ty) {
-        let path_segment = match ty.node {
-            hir::TyPath(hir::QPath::Resolved(_, ref path)) => path.segments.last(),
-            hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => Some(&**segment),
+        let def_and_segment = match ty.node {
+            hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
+                Some((path.def, path.segments.last().unwrap()))
+            }
+            hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => {
+                Some((self.tcx.tables().type_relative_path_defs[&ty.id], &**segment))
+            }
             _ => None
         };
-        if let Some(segment) = path_segment {
-            match self.tcx.expect_def(ty.id) {
+        if let Some((def, segment)) = def_and_segment {
+            match def {
                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
                     // Public
                 }
@@ -1005,7 +1021,7 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
 
     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
         // Non-local means public (private items can't leave their crate, modulo bugs)
-        let def_id = self.tcx.expect_def(trait_ref.ref_id).def_id();
+        let def_id = trait_ref.path.def.def_id();
         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
             let item = self.tcx.map.expect_item(node_id);
             let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 30d25c7ccec..058c8266a35 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1201,11 +1201,11 @@ impl<'a> ty::NodeIdTree for Resolver<'a> {
 }
 
 impl<'a> hir::lowering::Resolver for Resolver<'a> {
-    fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def {
+    fn resolve_generated_global_path(&mut self, path: &mut hir::Path, is_value: bool) {
         let namespace = if is_value { ValueNS } else { TypeNS };
         match self.resolve_crate_relative_path(path.span, &path.segments, namespace) {
-            Ok(binding) => binding.def(),
-            Err(true) => Def::Err,
+            Ok(binding) => path.def = binding.def(),
+            Err(true) => {}
             Err(false) => {
                 let path_name = &format!("{}", path);
                 let error =
@@ -1218,7 +1218,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
                         def: Def::Err,
                     };
                 resolve_error(self, path.span, error);
-                Def::Err
             }
         }
     }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 53b05051deb..3e7ca155da0 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -274,12 +274,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
     }
 
     fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
-        self.tcx.expect_def_or_none(ref_id).and_then(|def| {
-            match def {
-                Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
-                def => Some(def.def_id()),
-            }
-        })
+        match self.save_ctxt.get_path_def(ref_id) {
+            Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
+            def => Some(def.def_id()),
+        }
     }
 
     fn process_def_kind(&mut self,
@@ -292,7 +290,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             return;
         }
 
-        let def = self.tcx.expect_def(ref_id);
+        let def = self.save_ctxt.get_path_def(ref_id);
         match def {
             Def::Mod(_) => {
                 self.dumper.mod_ref(ModRefData {
@@ -919,7 +917,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
 
         // Modules or types in the path prefix.
-        match self.tcx.expect_def(id) {
+        match self.save_ctxt.get_path_def(id) {
             Def::Method(did) => {
                 let ti = self.tcx.associated_item(did);
                 if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
@@ -998,7 +996,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         return;
                     }
                 };
-                let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
+                let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
 
                 for &Spanned { node: ref field, span } in fields {
                     let sub_span = self.span.span_for_first_ident(span);
@@ -1370,7 +1368,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                         return;
                     }
                 };
-                let def = self.tcx.expect_def(hir_expr.id);
+                let def = self.save_ctxt.get_path_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
             ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args),
@@ -1480,7 +1478,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
 
         // process collected paths
         for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
-            match self.tcx.expect_def(id) {
+            match self.save_ctxt.get_path_def(id) {
                 Def::Local(def_id) => {
                     let id = self.tcx.map.as_local_node_id(def_id).unwrap();
                     let mut value = if immut == ast::Mutability::Immutable {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 3c6f67f0c88..e79ca6721db 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -42,8 +42,8 @@ pub mod external_data;
 pub mod span_utils;
 
 use rustc::hir;
-use rustc::hir::map::{Node, NodeItem};
 use rustc::hir::def::Def;
+use rustc::hir::map::Node;
 use rustc::hir::def_id::DefId;
 use rustc::session::config::CrateType::CrateTypeExecutable;
 use rustc::ty::{self, TyCtxt};
@@ -318,7 +318,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let (qualname, parent_scope, decl_id, vis, docs) =
           match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
             Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
-                Some(NodeItem(item)) => {
+                Some(Node::NodeItem(item)) => {
                     match item.node {
                         hir::ItemImpl(.., ref ty, _) => {
                             let mut result = String::from("<");
@@ -358,7 +358,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
                 Some(def_id) => {
                     match self.tcx.map.get_if_local(def_id) {
-                        Some(NodeItem(item)) => {
+                        Some(Node::NodeItem(item)) => {
                             (format!("::{}", self.tcx.item_path_str(def_id)),
                              Some(def_id), None,
                              From::from(&item.vis),
@@ -497,13 +497,41 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
-        let resolution = self.tcx.expect_resolution(id);
-        if resolution.depth != 0 {
-            return None;
+    pub fn get_path_def(&self, id: NodeId) -> Def {
+        match self.tcx.map.get(id) {
+            Node::NodeTraitRef(tr) => tr.path.def,
+
+            Node::NodeItem(&hir::Item { node: hir::ItemUse(ref path, _), .. }) |
+            Node::NodeVisibility(&hir::Visibility::Restricted { ref path, .. }) => path.def,
+
+            Node::NodeExpr(&hir::Expr { node: hir::ExprPath(ref qpath), .. }) |
+            Node::NodeExpr(&hir::Expr { node: hir::ExprStruct(ref qpath, ..), .. }) |
+            Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) |
+            Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) |
+            Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => {
+                self.tcx.tables().qpath_def(qpath, id)
+            }
+
+            Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => {
+                Def::Local(def_id)
+            }
+
+            Node::NodeTy(&hir::Ty { node: hir::TyPath(ref qpath), .. }) => {
+                match *qpath {
+                    hir::QPath::Resolved(_, ref path) => path.def,
+                    hir::QPath::TypeRelative(..) => {
+                        // FIXME(eddyb) Avoid keeping associated type resolutions.
+                        self.tcx.tables().type_relative_path_defs[&id]
+                    }
+                }
+            }
+
+            _ => Def::Err
         }
-        let def = resolution.base_def;
+    }
 
+    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
+        let def = self.get_path_def(id);
         let sub_span = self.span_utils.span_for_last_ident(path.span);
         filter!(self.span_utils, sub_span, path.span, None);
         match def {
@@ -647,8 +675,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     }
 
     fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
-        match self.tcx.expect_def(ref_id) {
-            Def::PrimTy(_) | Def::SelfTy(..) => None,
+        match self.get_path_def(ref_id) {
+            Def::PrimTy(_) | Def::SelfTy(..) | Def::Err => None,
             def => Some(def.def_id()),
         }
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7d02678679a..646f941deae 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -50,7 +50,7 @@
 
 use rustc_const_eval::eval_length;
 use hir::{self, SelfKind};
-use hir::def::{Def, PathResolution};
+use hir::def::Def;
 use hir::def_id::DefId;
 use hir::print as pprust;
 use middle::resolve_lifetime as rl;
@@ -678,7 +678,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
         let path = &trait_ref.path;
-        match self.tcx().expect_def(trait_ref.ref_id) {
+        match path.def {
             Def::Trait(trait_def_id) => trait_def_id,
             Def::Err => {
                 self.tcx().sess.fatal("cannot continue compilation due to previous error");
@@ -953,24 +953,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let tcx = self.tcx();
         match ty.node {
             hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
-                let resolution = tcx.expect_resolution(ty.id);
-                match resolution.base_def {
-                    Def::Trait(trait_def_id) if resolution.depth == 0 => {
-                        self.trait_path_to_object_type(rscope,
-                                                       path.span,
-                                                       trait_def_id,
-                                                       ty.id,
-                                                       path.segments.last().unwrap(),
-                                                       span,
-                                                       partition_bounds(tcx, span, bounds))
-                    }
-                    _ => {
-                        struct_span_err!(tcx.sess, ty.span, E0172,
-                                  "expected a reference to a trait")
-                            .span_label(ty.span, &format!("expected a trait"))
-                            .emit();
-                        tcx.types.err
-                    }
+                if let Def::Trait(trait_def_id) = path.def {
+                    self.trait_path_to_object_type(rscope,
+                                                   path.span,
+                                                   trait_def_id,
+                                                   ty.id,
+                                                   path.segments.last().unwrap(),
+                                                   span,
+                                                   partition_bounds(tcx, span, bounds))
+                } else {
+                    struct_span_err!(tcx.sess, ty.span, E0172,
+                                     "expected a reference to a trait")
+                        .span_label(ty.span, &format!("expected a trait"))
+                        .emit();
+                    tcx.types.err
                 }
             }
             _ => {
@@ -1412,55 +1408,54 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
     }
 
-    // Check a type Def and convert it to a Ty.
+    // Check a type Path and convert it to a Ty.
     pub fn def_to_ty(&self,
                      rscope: &RegionScope,
-                     span: Span,
-                     def: Def,
                      opt_self_ty: Option<Ty<'tcx>>,
+                     path: &hir::Path,
                      path_id: ast::NodeId,
-                     path_segments: &[hir::PathSegment],
                      permit_variants: bool)
                      -> Ty<'tcx> {
         let tcx = self.tcx();
 
         debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})",
-               def, opt_self_ty, path_segments);
+               path.def, opt_self_ty, path.segments);
 
-        match def {
+        let span = path.span;
+        match path.def {
             Def::Trait(trait_def_id) => {
                 // N.B. this case overlaps somewhat with
                 // TyObjectSum, see that fn for details
 
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments.split_last().unwrap().1);
+                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
 
                 self.trait_path_to_object_type(rscope,
                                                span,
                                                trait_def_id,
                                                path_id,
-                                               path_segments.last().unwrap(),
+                                               path.segments.last().unwrap(),
                                                span,
                                                partition_bounds(tcx, span, &[]))
             }
             Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments.split_last().unwrap().1);
-                self.ast_path_to_ty(rscope, span, did, path_segments.last().unwrap())
+                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+                self.ast_path_to_ty(rscope, span, did, path.segments.last().unwrap())
             }
             Def::Variant(did) if permit_variants => {
                 // Convert "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments.split_last().unwrap().1);
+                tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(rscope,
                                     span,
                                     tcx.parent_def_id(did).unwrap(),
-                                    path_segments.last().unwrap())
+                                    path.segments.last().unwrap())
             }
             Def::TyParam(did) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments);
+                tcx.prohibit_type_params(&path.segments);
 
                 let node_id = tcx.map.as_local_node_id(did).unwrap();
                 let param = tcx.ty_param_defs.borrow().get(&node_id)
@@ -1483,7 +1478,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // Self in impl (we know the concrete type).
 
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments);
+                tcx.prohibit_type_params(&path.segments);
                 let ty = tcx.item_type(def_id);
                 if let Some(free_substs) = self.get_free_substs() {
                     ty.subst(tcx, free_substs)
@@ -1494,22 +1489,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Def::SelfTy(Some(_), None) => {
                 // Self in trait.
                 assert_eq!(opt_self_ty, None);
-                tcx.prohibit_type_params(path_segments);
+                tcx.prohibit_type_params(&path.segments);
                 tcx.mk_self_type()
             }
             Def::AssociatedTy(def_id) => {
-                tcx.prohibit_type_params(&path_segments[..path_segments.len()-2]);
+                tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
                 let trait_did = tcx.parent_def_id(def_id).unwrap();
                 self.qpath_to_ty(rscope,
                                  span,
                                  opt_self_ty,
                                  trait_did,
-                                 &path_segments[path_segments.len()-2],
-                                 path_segments.last().unwrap())
+                                 &path.segments[path.segments.len()-2],
+                                 path.segments.last().unwrap())
             }
             Def::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                tcx.prim_ty_to_ty(path_segments, prim_ty)
+                tcx.prim_ty_to_ty(&path.segments, prim_ty)
             }
             Def::Err => {
                 self.set_tainted_by_errors();
@@ -1518,7 +1513,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             _ => {
                 struct_span_err!(tcx.sess, span, E0248,
                            "found value `{}` used as a type",
-                            tcx.item_path_str(def.def_id()))
+                            tcx.item_path_str(path.def.def_id()))
                            .span_label(span, &format!("value used as a type"))
                            .emit();
                 return self.tcx().types.err;
@@ -1653,23 +1648,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| {
                     self.ast_ty_to_ty(rscope, qself)
                 });
-                self.def_to_ty(rscope,
-                               ast_ty.span,
-                               tcx.expect_def(ast_ty.id),
-                               opt_self_ty,
-                               ast_ty.id,
-                               &path.segments,
-                               false)
+                self.def_to_ty(rscope, opt_self_ty, path, ast_ty.id, false)
             }
             hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
                 let ty = self.ast_ty_to_ty(rscope, qself);
 
-                let def = tcx.expect_def_or_none(qself.id).unwrap_or(Def::Err);
+                let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node {
+                    path.def
+                } else {
+                    Def::Err
+                };
                 let (ty, def) = self.associated_path_def_to_ty(ast_ty.span, ty, def, segment);
 
                 // Write back the new resolution.
-                tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def));
+                tcx.tables.borrow_mut().type_relative_path_defs.insert(ast_ty.id, def);
 
                 ty
             }
@@ -2007,7 +2000,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     for ast_bound in ast_bounds {
         match *ast_bound {
             hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
-                match tcx.expect_def(b.trait_ref.ref_id) {
+                match b.trait_ref.path.def {
                     Def::Trait(trait_did) => {
                         if tcx.try_add_builtin_trait(trait_did,
                                                      &mut builtin_bounds) {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 3e62b22d36f..9381d653ed2 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.demand_eqtype(pat.span, expected, rhs_ty);
                 common_type
             }
-            PatKind::Binding(bm, _, ref sub) => {
+            PatKind::Binding(bm, def_id, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
                 match bm {
                     hir::BindByRef(mutbl) => {
@@ -130,16 +130,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // if there are multiple arms, make sure they all agree on
                 // what the type of the binding `x` ought to be
-                match tcx.expect_def(pat.id) {
-                    Def::Err => {}
-                    Def::Local(def_id) => {
-                        let var_id = tcx.map.as_local_node_id(def_id).unwrap();
-                        if var_id != pat.id {
-                            let vt = self.local_ty(pat.span, var_id);
-                            self.demand_eqtype(pat.span, vt, typ);
-                        }
-                    }
-                    d => bug!("bad def for pattern binding `{:?}`", d)
+                let var_id = tcx.map.as_local_node_id(def_id).unwrap();
+                if var_id != pat.id {
+                    let vt = self.local_ty(pat.span, var_id);
+                    self.demand_eqtype(pat.span, vt, typ);
                 }
 
                 if let Some(ref p) = *sub {
@@ -373,7 +367,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // want to use the *precise* type of the discriminant, *not* some
         // supertype, as the "discriminant type" (issue #23116).
         let contains_ref_bindings = arms.iter()
-                                        .filter_map(|a| tcx.arm_contains_ref_binding(a))
+                                        .filter_map(|a| a.contains_ref_binding())
                                         .max_by_key(|m| match *m {
                                             hir::MutMutable => 1,
                                             hir::MutImmutable => 0,
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 3ffbbd1be80..fdf496b7c86 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -218,12 +218,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 if let hir::ExprCall(ref expr, _) = call_expr.node {
-                    let tcx = self.tcx;
-                    if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
-                        if pr.depth == 0 && pr.base_def != Def::Err {
-                            if let Some(span) = tcx.map.span_if_local(pr.base_def.def_id()) {
-                                err.span_note(span, "defined here");
-                            }
+                    let def = if let hir::ExprPath(ref qpath) = expr.node {
+                        self.tcx.tables().qpath_def(qpath, expr.id)
+                    } else {
+                        Def::Err
+                    };
+                    if def != Def::Err {
+                        if let Some(span) = self.tcx.map.span_if_local(def.def_id()) {
+                            err.span_note(span, "defined here");
                         }
                     }
                 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 33b123d0a6d..6bc37f5c44d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -83,9 +83,8 @@ use self::TupleArgumentsFlag::*;
 use astconv::{AstConv, ast_region_to_region};
 use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
-use hir::def::{Def, CtorKind, PathResolution};
+use hir::def::{Def, CtorKind};
 use hir::def_id::{DefId, LOCAL_CRATE};
-use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin,
                    TypeTrace, type_variable};
 use rustc::ty::subst::{Kind, Subst, Substs};
@@ -711,7 +710,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
 
     // Add pattern bindings.
     fn visit_pat(&mut self, p: &'gcx hir::Pat) {
-        if let PatKind::Binding(_, ref path1, _) = p.node {
+        if let PatKind::Binding(_, _, ref path1, _) = p.node {
             let var_ty = self.assign(p.span, p.id, None);
 
             self.fcx.require_type_is_sized(var_ty, p.span,
@@ -796,7 +795,7 @@ 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(&input.pat, |_bm, pat_id, sp, _path| {
+            input.pat.each_binding(|_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));
             });
@@ -3627,72 +3626,58 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               }
               tcx.mk_nil()
           }
-          hir::ExprBreak(ref label_opt, ref expr_opt) => {
-            let loop_id = if label_opt.is_some() {
-                let loop_def = tcx.expect_def(expr.id);
-                if let Def::Label(loop_id) = loop_def {
-                    Some(Some(loop_id))
-                } else if loop_def == Def::Err {
-                    // an error was already printed, so just ignore it
-                    None
+          hir::ExprBreak(label, ref expr_opt) => {
+            let loop_id = label.map(|l| l.loop_id);
+            let coerce_to = {
+                let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+                enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+            };
+            if let Some(coerce_to) = coerce_to {
+                let e_ty;
+                let cause;
+                if let Some(ref e) = *expr_opt {
+                    // Recurse without `enclosing_loops` borrowed.
+                    e_ty = self.check_expr_with_hint(e, coerce_to);
+                    cause = self.misc(e.span);
+                    // Notably, the recursive call may alter coerce_to - must not keep using it!
                 } else {
-                    span_bug!(expr.span, "break label resolved to a non-label");
+                    // `break` without argument acts like `break ()`.
+                    e_ty = tcx.mk_nil();
+                    cause = self.misc(expr.span);
                 }
-            } else {
-                Some(None)
-            };
-            if let Some(loop_id) = loop_id {
-                let coerce_to = {
-                    let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                    enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
-                };
-                if let Some(coerce_to) = coerce_to {
-                    let e_ty;
-                    let cause;
-                    if let Some(ref e) = *expr_opt {
-                        // Recurse without `enclosing_loops` borrowed.
-                        e_ty = self.check_expr_with_hint(e, coerce_to);
-                        cause = self.misc(e.span);
-                        // Notably, the recursive call may alter coerce_to - must not keep using it!
-                    } else {
-                        // `break` without argument acts like `break ()`.
-                        e_ty = tcx.mk_nil();
-                        cause = self.misc(expr.span);
-                    }
-                    let mut enclosing_loops = self.enclosing_loops.borrow_mut();
-                    let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+                let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+                let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
 
-                    let result = if let Some(ref e) = *expr_opt {
-                        // Special-case the first element, as it has no "previous expressions".
-                        let result = if !ctxt.may_break {
-                            self.try_coerce(e, e_ty, ctxt.coerce_to)
-                        } else {
-                            self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(),
-                                                       ctxt.unified, e, e_ty)
-                        };
-
-                        ctxt.break_exprs.push(e);
-                        result
+                let result = if let Some(ref e) = *expr_opt {
+                    // Special-case the first element, as it has no "previous expressions".
+                    let result = if !ctxt.may_break {
+                        self.try_coerce(e, e_ty, ctxt.coerce_to)
                     } else {
-                        self.eq_types(true, &cause, e_ty, ctxt.unified)
-                            .map(|InferOk { obligations, .. }| {
-                                // FIXME(#32730) propagate obligations
-                                assert!(obligations.is_empty());
-                                e_ty
-                            })
+                        self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(),
+                                                   ctxt.unified, e, e_ty)
                     };
-                    match result {
-                        Ok(ty) => ctxt.unified = ty,
-                        Err(err) => {
-                            self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
-                        }
-                    }
 
-                    ctxt.may_break = true;
+                    ctxt.break_exprs.push(e);
+                    result
+                } else {
+                    self.eq_types(true, &cause, e_ty, ctxt.unified)
+                        .map(|InferOk { obligations, .. }| {
+                            // FIXME(#32730) propagate obligations
+                            assert!(obligations.is_empty());
+                            e_ty
+                        })
+                };
+                match result {
+                    Ok(ty) => ctxt.unified = ty,
+                    Err(err) => {
+                        self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
+                    }
                 }
-                // Otherwise, we failed to find the enclosing loop; this can only happen if the
-                // `break` was not inside a loop at all, which is caught by the loop-checking pass.
+
+                ctxt.may_break = true;
             }
+            // Otherwise, we failed to find the enclosing loop; this can only happen if the
+            // `break` was not inside a loop at all, which is caught by the loop-checking pass.
             tcx.types.never
           }
           hir::ExprAgain(_) => { tcx.types.never }
@@ -4006,7 +3991,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
-    // The newly resolved definition is written into `def_map`.
+    // The newly resolved definition is written into `type_relative_path_defs`.
     fn finish_resolving_struct_path(&self,
                                     qpath: &hir::QPath,
                                     path_span: Span,
@@ -4016,25 +4001,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match *qpath {
             hir::QPath::Resolved(ref maybe_qself, ref path) => {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let def = self.tcx.expect_def(node_id);
-                let ty = AstConv::def_to_ty(self, self,
-                                            path.span,
-                                            def,
-                                            opt_self_ty,
-                                            node_id,
-                                            &path.segments,
-                                            true);
-                (def, ty)
+                let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, node_id, true);
+                (path.def, ty)
             }
             hir::QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
-                let def = self.tcx.expect_def_or_none(qself.id).unwrap_or(Def::Err);
+                let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node {
+                    path.def
+                } else {
+                    Def::Err
+                };
                 let (ty, def) = AstConv::associated_path_def_to_ty(self, path_span,
                                                                    ty, def, segment);
 
                 // Write back the new resolution.
-                self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def));
+                self.tcx.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
 
                 (def, ty)
             }
@@ -4042,7 +4024,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Resolve associated value path into a base type and associated constant or method definition.
-    // The newly resolved definition is written into `def_map`.
+    // The newly resolved definition is written into `type_relative_path_defs`.
     pub fn resolve_ty_and_def_ufcs<'b>(&self,
                                        qpath: &'b hir::QPath,
                                        node_id: ast::NodeId,
@@ -4051,7 +4033,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     {
         let (ty, item_segment) = match *qpath {
             hir::QPath::Resolved(ref opt_qself, ref path) => {
-                return (self.tcx.expect_def(node_id),
+                return (path.def,
                         opt_qself.as_ref().map(|qself| self.to_ty(qself)),
                         &path.segments[..]);
             }
@@ -4075,7 +4057,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Write back the new resolution.
-        self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def));
+        self.tcx.tables.borrow_mut().type_relative_path_defs.insert(node_id, def);
         (def, Some(ty), slice::ref_slice(&**item_segment))
     }
 
@@ -4083,7 +4065,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   local: &'gcx hir::Local,
                                   init: &'gcx hir::Expr) -> Ty<'tcx>
     {
-        let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
+        let ref_bindings = local.pat.contains_ref_binding();
 
         let local_ty = self.local_ty(init.span, local.id);
         if let Some(m) = ref_bindings {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 2b1bea89c52..ca33682480c 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -92,7 +92,6 @@ use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
 use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
-use hir::pat_util;
 use rustc::ty::adjustment;
 use rustc::ty::wf::ImpliedBound;
 
@@ -434,7 +433,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(pat, |_, id, span, _| {
+        pat.each_binding(|_, 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/collect.rs b/src/librustc_typeck/collect.rs
index b83e453b2de..493f9d96fe0 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -542,11 +542,10 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       param_id: ast::NodeId)
                       -> bool
 {
-    if let hir::TyPath(hir::QPath::Resolved(None, _)) = ast_ty.node {
-        let path_res = tcx.expect_resolution(ast_ty.id);
-        match path_res.base_def {
+    if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
+        match path.def {
             Def::SelfTy(Some(def_id), None) |
-            Def::TyParam(def_id) if path_res.depth == 0 => {
+            Def::TyParam(def_id) => {
                 def_id == tcx.map.local_def_id(param_id)
             }
             _ => false
@@ -1625,8 +1624,7 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
         Some(ref tpb) => {
             // FIXME(#8559) currently requires the unbound to be built-in.
             if let Ok(kind_id) = kind_id {
-                let trait_def = tcx.expect_def(tpb.ref_id);
-                if trait_def != Def::Trait(kind_id) {
+                if tpb.path.def != Def::Trait(kind_id) {
                     tcx.sess.span_warn(span,
                                        "default bound relaxed for a type parameter, but \
                                        this does nothing because the given bound is not \
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index c5562ae3b7f..e3274611e5b 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -29,24 +29,21 @@ use clean::{self, GetDefId};
 
 use super::Clean;
 
-/// Attempt to inline the definition of a local node id into this AST.
+/// Attempt to inline a definition into this AST.
 ///
-/// This function will fetch the definition of the id specified, and if it is
-/// from another crate it will attempt to inline the documentation from the
-/// other crate into this crate.
+/// This function will fetch the definition specified, and if it is
+/// from another crate it will attempt to inline the documentation
+/// from the other crate into this crate.
 ///
 /// This is primarily used for `pub use` statements which are, in general,
 /// implementation details. Inlining the documentation should help provide a
 /// better experience when reading the documentation in this use case.
 ///
-/// The returned value is `None` if the `id` could not be inlined, and `Some`
-/// of a vector of items if it was successfully expanded.
-pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>)
+/// The returned value is `None` if the definition could not be inlined,
+/// and `Some` of a vector of items if it was successfully expanded.
+pub fn try_inline(cx: &DocContext, def: Def, into: Option<ast::Name>)
                   -> Option<Vec<clean::Item>> {
-    let def = match cx.tcx.expect_def_or_none(id) {
-        Some(def) => def,
-        None => return None,
-    };
+    if def == Def::Err { return None }
     let did = def.def_id();
     if did.is_local() { return None }
     try_inline_def(cx, def).map(|vec| {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5e1b12e80d4..0fda1f4bf10 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -667,6 +667,7 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self
                  bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
     Path {
         global: false,
+        def: Def::Err,
         segments: vec![PathSegment {
             name: name.to_string(),
             params: external_path_params(cx, trait_did, has_self, bindings, substs)
@@ -1728,13 +1729,12 @@ impl Clean<Type> for hir::Ty {
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(hir::QPath::Resolved(None, ref path)) => {
-                let def = cx.tcx.expect_def(self.id);
-                if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() {
+                if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
                     return new_ty;
                 }
 
                 let mut alias = None;
-                if let Def::TyAlias(def_id) = def {
+                if let Def::TyAlias(def_id) = path.def {
                     // Substitute private type aliases
                     if let Some(node_id) = cx.tcx.map.as_local_node_id(def_id) {
                         if !cx.access_levels.borrow().is_exported(def_id) {
@@ -1748,7 +1748,7 @@ impl Clean<Type> for hir::Ty {
                     let mut ty_substs = FxHashMap();
                     let mut lt_substs = FxHashMap();
                     for (i, ty_param) in generics.ty_params.iter().enumerate() {
-                        let ty_param_def = cx.tcx.expect_def(ty_param.id);
+                        let ty_param_def = Def::TyParam(cx.tcx.map.local_def_id(ty_param.id));
                         if let Some(ty) = provided_params.types().get(i).cloned()
                                                                         .cloned() {
                             ty_substs.insert(ty_param_def, ty.unwrap().clean(cx));
@@ -1772,6 +1772,7 @@ impl Clean<Type> for hir::Ty {
                 let trait_path = hir::Path {
                     span: p.span,
                     global: p.global,
+                    def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
                     segments: segments.into(),
                 };
                 Type::QPath {
@@ -1784,6 +1785,10 @@ impl Clean<Type> for hir::Ty {
                 let trait_path = hir::Path {
                     span: self.span,
                     global: false,
+                    def: cx.tcx_opt().map_or(Def::Err, |tcx| {
+                        let def_id = tcx.tables().type_relative_path_defs[&self.id].def_id();
+                        Def::Trait(tcx.associated_item(def_id).container.id())
+                    }),
                     segments: vec![].into(),
                 };
                 Type::QPath {
@@ -2194,6 +2199,7 @@ impl Clean<Span> for syntax_pos::Span {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct Path {
     pub global: bool,
+    pub def: Def,
     pub segments: Vec<PathSegment>,
 }
 
@@ -2201,6 +2207,7 @@ impl Path {
     pub fn singleton(name: String) -> Path {
         Path {
             global: false,
+            def: Def::Err,
             segments: vec![PathSegment {
                 name: name,
                 params: PathParameters::AngleBracketed {
@@ -2221,6 +2228,7 @@ impl Clean<Path> for hir::Path {
     fn clean(&self, cx: &DocContext) -> Path {
         Path {
             global: self.global,
+            def: self.def,
             segments: self.segments.clean(cx),
         }
     }
@@ -2591,15 +2599,15 @@ impl Clean<Vec<Item>> for doctree::Import {
         });
         let path = self.path.clean(cx);
         let inner = if self.glob {
-            Import::Glob(resolve_use_source(cx, path, self.id))
+            Import::Glob(resolve_use_source(cx, path))
         } else {
             let name = self.name;
             if !denied {
-                if let Some(items) = inline::try_inline(cx, self.id, Some(name)) {
+                if let Some(items) = inline::try_inline(cx, path.def, Some(name)) {
                     return items;
                 }
             }
-            Import::Simple(name.clean(cx), resolve_use_source(cx, path, self.id))
+            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
         };
         vec![Item {
             name: None,
@@ -2697,7 +2705,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
 
     match p.node {
         PatKind::Wild => "_".to_string(),
-        PatKind::Binding(_, ref p, _) => p.node.to_string(),
+        PatKind::Binding(_, _, ref p, _) => p.node.to_string(),
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
         PatKind::Struct(ref name, ref fields, etc) => {
             format!("{} {{ {}{} }}", qpath_to_string(name),
@@ -2727,15 +2735,13 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
-/// Given a Type, resolve it using the def_map
+/// Given a type Path, resolve it to a Type using the TyCtxt
 fn resolve_type(cx: &DocContext,
                 path: Path,
                 id: ast::NodeId) -> Type {
     debug!("resolve_type({:?},{:?})", path, id);
-    let def = cx.tcx.expect_def(id);
-    debug!("resolve_type: def={:?}", def);
 
-    let is_generic = match def {
+    let is_generic = match path.def {
         Def::PrimTy(p) => match p {
             hir::TyStr => return Primitive(PrimitiveType::Str),
             hir::TyBool => return Primitive(PrimitiveType::Bool),
@@ -2750,7 +2756,7 @@ fn resolve_type(cx: &DocContext,
         Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
         _ => false,
     };
-    let did = register_def(&*cx, def);
+    let did = register_def(&*cx, path.def);
     ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
 }
 
@@ -2782,17 +2788,17 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
     did
 }
 
-fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
+fn resolve_use_source(cx: &DocContext, path: Path) -> ImportSource {
     ImportSource {
+        did: if path.def == Def::Err {
+            None
+        } else {
+            Some(register_def(cx, path.def))
+        },
         path: path,
-        did: resolve_def(cx, id),
     }
 }
 
-fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<DefId> {
-    cx.tcx.expect_def_or_none(id).map(|def| register_def(cx, def))
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Macro {
     pub source: String,
@@ -2896,6 +2902,7 @@ fn lang_struct(cx: &DocContext, did: Option<DefId>,
         did: did,
         path: Path {
             global: false,
+            def: Def::Err,
             segments: vec![PathSegment {
                 name: name.to_string(),
                 params: PathParameters::AngleBracketed {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index fcf747a7c17..4087b9a761f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -234,8 +234,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     /// and follows different rules.
     ///
     /// Returns true if the target has been inlined.
-    fn maybe_inline_local(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
-                  glob: bool, om: &mut Module, please_inline: bool) -> bool {
+    fn maybe_inline_local(&mut self,
+                          id: ast::NodeId,
+                          def: Def,
+                          renamed: Option<ast::Name>,
+                          glob: bool,
+                          om: &mut Module,
+                          please_inline: bool) -> bool {
 
         fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
             while let Some(id) = cx.tcx.map.get_enclosing_scope(node) {
@@ -251,7 +256,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         }
 
         let tcx = self.cx.tcx;
-        let def = tcx.expect_def(id);
+        if def == Def::Err {
+            return false;
+        }
         let def_did = def.def_id();
 
         let use_attrs = tcx.map.attrs(id);
@@ -368,13 +375,18 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                         }
                     });
                     let name = if is_glob { None } else { Some(name) };
-                    if self.maybe_inline_local(item.id, name, is_glob, om, please_inline) {
+                    if self.maybe_inline_local(item.id,
+                                               path.def,
+                                               name,
+                                               is_glob,
+                                               om,
+                                               please_inline) {
                         return;
                     }
                 }
 
                 om.imports.push(Import {
-                    name: item.name,
+                    name: name,
                     id: item.id,
                     vis: item.vis.clone(),
                     attrs: item.attrs.clone(),
diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs
index 1b6e4b1d289..e2acdcee3de 100644
--- a/src/test/compile-fail/issue-3521.rs
+++ b/src/test/compile-fail/issue-3521.rs
@@ -16,7 +16,7 @@ fn main() {
         Bar = foo
         //~^ ERROR attempt to use a non-constant value in a constant
         //~^^ ERROR constant evaluation error
-        //~| non-constant path in constant expression
+        //~| unresolved path in constant expression
     }
 
     println!("{}", Stuff::Bar);