about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2015-10-02 16:12:20 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2015-10-02 16:13:50 +0300
commit55d35f12ae7a73fcef1c59b5b2cc0142a557934c (patch)
tree476d9742426d7892a3f1e3aaaf1f907893bd0deb
parentdb817ceda4fe204261c9d1773dc137830e58e225 (diff)
parente82faeb65594302897223b2ca4ee6927fb54625f (diff)
Merge branch 'master' into metadiet
rlib sizes:
1445222 liballoc_jemalloc-bb943c5a.rlib
10664 liballoc_system-bb943c5a.rlib
143592 libarena-bb943c5a.rlib
3639102 libcollections-bb943c5a.rlib
16316910 libcore-bb943c5a.rlib
214154 libflate-bb943c5a.rlib
231440 libfmt_macros-bb943c5a.rlib
536976 libgetopts-bb943c5a.rlib
209672 libgraphviz-bb943c5a.rlib
408008 liblibc-bb943c5a.rlib
189610 liblog-bb943c5a.rlib
662184 librand-bb943c5a.rlib
605112 librbml-bb943c5a.rlib
1397820 librustc_back-bb943c5a.rlib
38383772 librustc-bb943c5a.rlib
12842 librustc_bitflags-bb943c5a.rlib
2297822 librustc_borrowck-bb943c5a.rlib
571064 librustc_data_structures-bb943c5a.rlib
9356542 librustc_driver-bb943c5a.rlib
9477226 librustc_front-bb943c5a.rlib
1605698 librustc_lint-bb943c5a.rlib
77111720 librustc_llvm-bb943c5a.rlib
4783848 librustc_mir-bb943c5a.rlib
3534256 librustc_platform_intrinsics-bb943c5a.rlib
593038 librustc_privacy-bb943c5a.rlib
3122202 librustc_resolve-bb943c5a.rlib
14185212 librustc_trans-bb943c5a.rlib
11940328 librustc_typeck-bb943c5a.rlib
1634264 librustc_unicode-bb943c5a.rlib
15564160 librustdoc-bb943c5a.rlib
8153964 libstd-bb943c5a.rlib
30589338 libsyntax-bb943c5a.rlib
897110 libterm-bb943c5a.rlib
1360662 libtest-bb943c5a.rlib
-rw-r--r--src/librustc/front/map/collector.rs344
-rw-r--r--src/librustc/front/map/definitions.rs263
-rw-r--r--src/librustc/front/map/mod.rs286
-rw-r--r--src/librustc/metadata/common.rs17
-rw-r--r--src/librustc/metadata/creader.rs7
-rw-r--r--src/librustc/metadata/csearch.rs101
-rw-r--r--src/librustc/metadata/cstore.rs22
-rw-r--r--src/librustc/metadata/decoder.rs256
-rw-r--r--src/librustc/metadata/encoder.rs429
-rw-r--r--src/librustc/metadata/index.rs224
-rw-r--r--src/librustc/metadata/tydecode.rs71
-rw-r--r--src/librustc/metadata/tyencode.rs2
-rw-r--r--src/librustc/middle/astencode.rs164
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/check_match.rs2
-rw-r--r--src/librustc/middle/check_static_recursion.rs56
-rw-r--r--src/librustc/middle/const_eval.rs55
-rw-r--r--src/librustc/middle/dead.rs64
-rw-r--r--src/librustc/middle/def.rs44
-rw-r--r--src/librustc/middle/def_id.rs58
-rw-r--r--src/librustc/middle/expr_use_visitor.rs14
-rw-r--r--src/librustc/middle/infer/mod.rs21
-rw-r--r--src/librustc/middle/lang_items.rs29
-rw-r--r--src/librustc/middle/liveness.rs10
-rw-r--r--src/librustc/middle/mem_categorization.rs6
-rw-r--r--src/librustc/middle/pat_util.rs4
-rw-r--r--src/librustc/middle/reachable.rs60
-rw-r--r--src/librustc/middle/stability.rs12
-rw-r--r--src/librustc/middle/traits/coherence.rs3
-rw-r--r--src/librustc/middle/traits/select.rs8
-rw-r--r--src/librustc/middle/ty/context.rs50
-rw-r--r--src/librustc/middle/ty/error.rs20
-rw-r--r--src/librustc/middle/ty/mod.rs83
-rw-r--r--src/librustc/middle/ty/sty.rs4
-rw-r--r--src/librustc/middle/ty/util.rs2
-rw-r--r--src/librustc/util/ppaux.rs28
-rw-r--r--src/librustc_borrowck/borrowck/fragments.rs4
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_driver/test.rs4
-rw-r--r--src/librustc_lint/bad_style.rs6
-rw-r--r--src/librustc_lint/builtin.rs80
-rw-r--r--src/librustc_lint/unused.rs4
-rw-r--r--src/librustc_mir/dump.rs3
-rw-r--r--src/librustc_mir/tcx/expr.rs9
-rw-r--r--src/librustc_privacy/lib.rs103
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs67
-rw-r--r--src/librustc_resolve/lib.rs33
-rw-r--r--src/librustc_resolve/record_exports.rs6
-rw-r--r--src/librustc_trans/back/link.rs29
-rw-r--r--src/librustc_trans/save/dump_csv.rs10
-rw-r--r--src/librustc_trans/save/mod.rs60
-rw-r--r--src/librustc_trans/save/recorder.rs37
-rw-r--r--src/librustc_trans/trans/_match.rs6
-rw-r--r--src/librustc_trans/trans/base.rs31
-rw-r--r--src/librustc_trans/trans/callee.rs27
-rw-r--r--src/librustc_trans/trans/closure.rs48
-rw-r--r--src/librustc_trans/trans/common.rs10
-rw-r--r--src/librustc_trans/trans/consts.rs16
-rw-r--r--src/librustc_trans/trans/debuginfo/metadata.rs9
-rw-r--r--src/librustc_trans/trans/debuginfo/mod.rs3
-rw-r--r--src/librustc_trans/trans/debuginfo/utils.rs9
-rw-r--r--src/librustc_trans/trans/expr.rs23
-rw-r--r--src/librustc_trans/trans/foreign.rs12
-rw-r--r--src/librustc_trans/trans/inline.rs13
-rw-r--r--src/librustc_trans/trans/monomorphize.rs30
-rw-r--r--src/librustc_typeck/astconv.rs34
-rw-r--r--src/librustc_typeck/check/_match.rs6
-rw-r--r--src/librustc_typeck/check/callee.rs3
-rw-r--r--src/librustc_typeck/check/closure.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs8
-rw-r--r--src/librustc_typeck/check/dropck.rs15
-rw-r--r--src/librustc_typeck/check/intrinsic.rs5
-rw-r--r--src/librustc_typeck/check/method/suggest.rs20
-rw-r--r--src/librustc_typeck/check/mod.rs47
-rw-r--r--src/librustc_typeck/check/upvar.rs33
-rw-r--r--src/librustc_typeck/check/wf.rs23
-rw-r--r--src/librustc_typeck/check/wfcheck.rs22
-rw-r--r--src/librustc_typeck/check/writeback.rs4
-rw-r--r--src/librustc_typeck/coherence/mod.rs55
-rw-r--r--src/librustc_typeck/coherence/orphan.rs5
-rw-r--r--src/librustc_typeck/coherence/overlap.rs15
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs3
-rw-r--r--src/librustc_typeck/collect.rs223
-rw-r--r--src/librustc_typeck/lib.rs10
-rw-r--r--src/librustc_typeck/variance.rs30
-rw-r--r--src/librustdoc/clean/mod.rs73
-rw-r--r--src/librustdoc/core.rs27
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/render.rs39
-rw-r--r--src/librustdoc/passes.rs39
-rw-r--r--src/librustdoc/test.rs8
-rw-r--r--src/librustdoc/visit_ast.rs20
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/test/compile-fail/borrowck-in-static.rs22
-rw-r--r--src/test/compile-fail/issue-28113.rs15
-rw-r--r--src/test/run-pass/issue-27890.rs16
96 files changed, 2489 insertions, 1859 deletions
diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs
new file mode 100644
index 00000000000..5f3148c7c33
--- /dev/null
+++ b/src/librustc/front/map/collector.rs
@@ -0,0 +1,344 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use super::MapEntry::*;
+
+use rustc_front::hir::*;
+use rustc_front::util;
+use rustc_front::visit::{self, Visitor};
+use middle::def_id::{CRATE_DEF_INDEX, DefIndex};
+use std::iter::repeat;
+use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
+use syntax::codemap::Span;
+
+/// A Visitor that walks over an AST and collects Node's into an AST
+/// Map.
+pub struct NodeCollector<'ast> {
+    pub map: Vec<MapEntry<'ast>>,
+    pub definitions: Definitions,
+    pub parent_node: NodeId,
+}
+
+impl<'ast> NodeCollector<'ast> {
+    pub fn root() -> NodeCollector<'ast> {
+        let mut collector = NodeCollector {
+            map: vec![],
+            definitions: Definitions::new(),
+            parent_node: CRATE_NODE_ID,
+        };
+        collector.insert_entry(CRATE_NODE_ID, RootCrate);
+
+        let result = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
+        assert_eq!(result, CRATE_DEF_INDEX);
+
+        collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
+
+        collector
+    }
+
+    pub fn extend(parent: &'ast InlinedParent,
+                  parent_node: NodeId,
+                  parent_def_path: DefPath,
+                  map: Vec<MapEntry<'ast>>,
+                  definitions: Definitions)
+                  -> NodeCollector<'ast> {
+        let mut collector = NodeCollector {
+            map: map,
+            parent_node: parent_node,
+            definitions: definitions,
+        };
+
+        collector.insert_entry(parent_node, RootInlinedParent(parent));
+        collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path));
+
+        collector
+    }
+
+    fn parent_def(&self) -> Option<DefIndex> {
+        let mut parent_node = Some(self.parent_node);
+        while let Some(p) = parent_node {
+            if let Some(q) = self.definitions.opt_def_index(p) {
+                return Some(q);
+            }
+            parent_node = self.map[p as usize].parent_node();
+        }
+        None
+    }
+
+    fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
+        let parent_def = self.parent_def();
+        self.definitions.create_def_with_parent(parent_def, node_id, data)
+    }
+
+    fn create_def_with_parent(&mut self,
+                              parent: Option<DefIndex>,
+                              node_id: NodeId,
+                              data: DefPathData)
+                              -> DefIndex {
+        self.definitions.create_def_with_parent(parent, node_id, data)
+    }
+
+    fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
+        debug!("ast_map: {:?} => {:?}", id, entry);
+        let len = self.map.len();
+        if id as usize >= len {
+            self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
+        }
+        self.map[id as usize] = entry;
+    }
+
+    fn insert_def(&mut self, id: NodeId, node: Node<'ast>, data: DefPathData) -> DefIndex {
+        self.insert(id, node);
+        self.create_def(id, data)
+    }
+
+    fn insert(&mut self, id: NodeId, node: Node<'ast>) {
+        let entry = MapEntry::from_node(self.parent_node, node);
+        self.insert_entry(id, entry);
+    }
+
+    fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
+        for a in &decl.inputs {
+            self.insert(a.id, NodeArg(&*a.pat));
+        }
+    }
+}
+
+impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
+    fn visit_item(&mut self, i: &'ast Item) {
+        // Pick the def data. This need not be unique, but the more
+        // information we encapsulate into
+        let def_data = match i.node {
+            ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl,
+            ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name),
+            ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name),
+            ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name),
+            _ => DefPathData::Misc,
+        };
+
+        self.insert_def(i.id, NodeItem(i), def_data);
+
+        let parent_node = self.parent_node;
+        self.parent_node = i.id;
+
+        match i.node {
+            ItemImpl(..) => {}
+            ItemEnum(ref enum_definition, _) => {
+                for v in &enum_definition.variants {
+                    let variant_def_index =
+                        self.insert_def(v.node.id,
+                                        NodeVariant(&**v),
+                                        DefPathData::EnumVariant(v.node.name));
+
+                    match v.node.kind {
+                        TupleVariantKind(ref args) => {
+                            for arg in args {
+                                self.create_def_with_parent(Some(variant_def_index),
+                                                            arg.id,
+                                                            DefPathData::PositionalField);
+                            }
+                        }
+                        StructVariantKind(ref def) => {
+                            for field in &def.fields {
+                                self.create_def_with_parent(
+                                    Some(variant_def_index),
+                                    field.node.id,
+                                    DefPathData::Field(field.node.kind));
+                            }
+                        }
+                    }
+                }
+            }
+            ItemForeignMod(..) => {
+            }
+            ItemStruct(ref struct_def, _) => {
+                // If this is a tuple-like struct, register the constructor.
+                if let Some(ctor_id) = struct_def.ctor_id {
+                    self.insert_def(ctor_id,
+                                    NodeStructCtor(&**struct_def),
+                                    DefPathData::StructCtor);
+                }
+
+                for field in &struct_def.fields {
+                    self.create_def(field.node.id, DefPathData::Field(field.node.kind));
+                }
+            }
+            ItemTrait(_, _, ref bounds, _) => {
+                for b in bounds.iter() {
+                    if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
+                        self.insert(t.trait_ref.ref_id, NodeItem(i));
+                    }
+                }
+            }
+            ItemUse(ref view_path) => {
+                match view_path.node {
+                    ViewPathList(_, ref paths) => {
+                        for path in paths {
+                            self.insert(path.node.id(), NodeItem(i));
+                        }
+                    }
+                    _ => ()
+                }
+            }
+            _ => {}
+        }
+        visit::walk_item(self, i);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
+        self.insert_def(foreign_item.id,
+                        NodeForeignItem(foreign_item),
+                        DefPathData::Value(foreign_item.name));
+
+        let parent_node = self.parent_node;
+        self.parent_node = foreign_item.id;
+        visit::walk_foreign_item(self, foreign_item);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_generics(&mut self, generics: &'ast Generics) {
+        for ty_param in generics.ty_params.iter() {
+            self.insert_def(ty_param.id,
+                            NodeTyParam(ty_param),
+                            DefPathData::TypeParam(ty_param.name));
+        }
+
+        visit::walk_generics(self, generics);
+    }
+
+    fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
+        let def_data = match ti.node {
+            MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name),
+            TypeTraitItem(..) => DefPathData::Type(ti.name),
+        };
+
+        self.insert(ti.id, NodeTraitItem(ti));
+        self.create_def(ti.id, def_data);
+
+        let parent_node = self.parent_node;
+        self.parent_node = ti.id;
+
+        match ti.node {
+            ConstTraitItem(_, Some(ref expr)) => {
+                self.create_def(expr.id, DefPathData::Initializer);
+            }
+            _ => { }
+        }
+
+        visit::walk_trait_item(self, ti);
+
+        self.parent_node = parent_node;
+    }
+
+    fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
+        let def_data = match ii.node {
+            MethodImplItem(..) | ConstImplItem(..) => DefPathData::Value(ii.name),
+            TypeImplItem(..) => DefPathData::Type(ii.name),
+        };
+
+        self.insert_def(ii.id, NodeImplItem(ii), def_data);
+
+        let parent_node = self.parent_node;
+        self.parent_node = ii.id;
+
+        match ii.node {
+            ConstImplItem(_, ref expr) => {
+                self.create_def(expr.id, DefPathData::Initializer);
+            }
+            _ => { }
+        }
+
+        visit::walk_impl_item(self, ii);
+
+        self.parent_node = parent_node;
+    }
+
+    fn visit_pat(&mut self, pat: &'ast Pat) {
+        let maybe_binding = match pat.node {
+            PatIdent(_, id, _) => Some(id.node),
+            _ => None
+        };
+
+        if let Some(id) = maybe_binding {
+            self.insert_def(pat.id, NodeLocal(pat), DefPathData::Binding(id.name));
+        } else {
+            self.insert(pat.id, NodePat(pat));
+        }
+
+        let parent_node = self.parent_node;
+        self.parent_node = pat.id;
+        visit::walk_pat(self, pat);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_expr(&mut self, expr: &'ast Expr) {
+        self.insert(expr.id, NodeExpr(expr));
+
+        match expr.node {
+            ExprClosure(..) => { self.create_def(expr.id, DefPathData::ClosureExpr); }
+            _ => { }
+        }
+
+        let parent_node = self.parent_node;
+        self.parent_node = expr.id;
+        visit::walk_expr(self, expr);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_stmt(&mut self, stmt: &'ast Stmt) {
+        let id = util::stmt_id(stmt);
+        self.insert(id, NodeStmt(stmt));
+        let parent_node = self.parent_node;
+        self.parent_node = id;
+        visit::walk_stmt(self, stmt);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
+                b: &'ast Block, s: Span, id: NodeId) {
+        assert_eq!(self.parent_node, id);
+        self.visit_fn_decl(fd);
+        visit::walk_fn(self, fk, fd, b, s);
+    }
+
+    fn visit_ty(&mut self, ty: &'ast Ty) {
+        match ty.node {
+            TyBareFn(ref fd) => {
+                self.visit_fn_decl(&*fd.decl);
+            }
+            _ => {}
+        }
+        visit::walk_ty(self, ty);
+    }
+
+    fn visit_block(&mut self, block: &'ast Block) {
+        self.insert(block.id, NodeBlock(block));
+        let parent_node = self.parent_node;
+        self.parent_node = block.id;
+        visit::walk_block(self, block);
+        self.parent_node = parent_node;
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        self.insert(lifetime.id, NodeLifetime(lifetime));
+    }
+
+    fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
+        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
+        self.visit_lifetime(&def.lifetime);
+    }
+
+    fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
+        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
+    }
+}
+
diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs
new file mode 100644
index 00000000000..c1eb5f1f118
--- /dev/null
+++ b/src/librustc/front/map/definitions.rs
@@ -0,0 +1,263 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::{DefId, DefIndex};
+use rustc_data_structures::fnv::FnvHashMap;
+use rustc_front::hir;
+use syntax::ast;
+use syntax::parse::token::InternedString;
+use util::nodemap::NodeMap;
+
+#[derive(Clone)]
+pub struct Definitions {
+    data: Vec<DefData>,
+    key_map: FnvHashMap<DefKey, DefIndex>,
+    node_map: NodeMap<DefIndex>,
+}
+
+/// A unique identifier that we can use to lookup a definition
+/// precisely. It combines the index of the definition's parent (if
+/// any) with a `DisambiguatedDefPathData`.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct DefKey {
+    /// Parent path.
+    pub parent: Option<DefIndex>,
+
+    /// Identifier of this node.
+    pub disambiguated_data: DisambiguatedDefPathData,
+}
+
+/// Pair of `DefPathData` and an integer disambiguator. The integer is
+/// normally 0, but in the event that there are multiple defs with the
+/// same `parent` and `data`, we use this field to disambiguate
+/// between them. This introduces some artificial ordering dependency
+/// but means that if you have (e.g.) two impls for the same type in
+/// the same module, they do get distinct def-ids.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct DisambiguatedDefPathData {
+    pub data: DefPathData,
+    pub disambiguator: u32
+}
+
+/// For each definition, we track the following data.  A definition
+/// here is defined somewhat circularly as "something with a def-id",
+/// but it generally corresponds to things like structs, enums, etc.
+/// There are also some rather random cases (like const initializer
+/// expressions) that are mostly just leftovers.
+#[derive(Clone, Debug)]
+pub struct DefData {
+    pub key: DefKey,
+
+    /// Local ID within the HIR.
+    pub node_id: ast::NodeId,
+}
+
+pub type DefPath = Vec<DisambiguatedDefPathData>;
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DefPathData {
+    // Root: these should only be used for the root nodes, because
+    // they are treated specially by the `def_path` function.
+    CrateRoot,
+    InlinedRoot(DefPath),
+
+    // Catch-all for random DefId things like DUMMY_NODE_ID
+    Misc,
+
+    // Different kinds of items and item-like things:
+    Impl,
+    Type(ast::Name),
+    Mod(ast::Name),
+    Value(ast::Name),
+    MacroDef(ast::Name),
+    ClosureExpr,
+
+    // Subportions of items
+    TypeParam(ast::Name),
+    LifetimeDef(ast::Name),
+    EnumVariant(ast::Name),
+    PositionalField,
+    Field(hir::StructFieldKind),
+    StructCtor, // implicit ctor for a tuple-like struct
+    Initializer, // initializer for a const
+    Binding(ast::Name), // pattern binding
+
+    // An external crate that does not have an `extern crate` in this
+    // crate.
+    DetachedCrate(ast::Name),
+}
+
+impl Definitions {
+    pub fn new() -> Definitions {
+        Definitions {
+            data: vec![],
+            key_map: FnvHashMap(),
+            node_map: NodeMap(),
+        }
+    }
+
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+
+    pub fn def_key(&self, index: DefIndex) -> DefKey {
+        self.data[index.as_usize()].key.clone()
+    }
+
+    /// Returns the path from the crate root to `index`. The root
+    /// nodes are not included in the path (i.e., this will be an
+    /// empty vector for the crate root). For an inlined item, this
+    /// will be the path of the item in the external crate (but the
+    /// path will begin with the path to the external crate).
+    pub fn def_path(&self, index: DefIndex) -> DefPath {
+        make_def_path(index, |p| self.def_key(p))
+    }
+
+    pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
+        self.node_map.get(&node).cloned()
+    }
+
+    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
+        self.opt_def_index(node).map(DefId::local)
+    }
+
+    pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
+        if def_id.krate == LOCAL_CRATE {
+            assert!(def_id.index.as_usize() < self.data.len());
+            Some(self.data[def_id.index.as_usize()].node_id)
+        } else {
+            None
+        }
+    }
+
+    pub fn create_def_with_parent(&mut self,
+                                  parent: Option<DefIndex>,
+                                  node_id: ast::NodeId,
+                                  data: DefPathData)
+                                  -> DefIndex {
+        assert!(!self.node_map.contains_key(&node_id),
+                "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+                node_id,
+                data,
+                self.data[self.node_map[&node_id].as_usize()]);
+
+        // Find a unique DefKey. This basically means incrementing the disambiguator
+        // until we get no match.
+        let mut key = DefKey {
+            parent: parent,
+            disambiguated_data: DisambiguatedDefPathData {
+                data: data,
+                disambiguator: 0
+            }
+        };
+
+        while self.key_map.contains_key(&key) {
+            key.disambiguated_data.disambiguator += 1;
+        }
+
+        // Create the definition.
+        let index = DefIndex::new(self.data.len());
+        self.data.push(DefData { key: key.clone(), node_id: node_id });
+        self.node_map.insert(node_id, index);
+        self.key_map.insert(key, index);
+
+        index
+    }
+}
+
+impl DefPathData {
+    pub fn as_interned_str(&self) -> InternedString {
+        use self::DefPathData::*;
+        match *self {
+            Type(name) |
+            Mod(name) |
+            Value(name) |
+            MacroDef(name) |
+            TypeParam(name) |
+            LifetimeDef(name) |
+            EnumVariant(name) |
+            DetachedCrate(name) |
+            Binding(name) => {
+                name.as_str()
+            }
+
+            Field(hir::StructFieldKind::NamedField(name, _)) => {
+                name.as_str()
+            }
+
+            PositionalField |
+            Field(hir::StructFieldKind::UnnamedField(_)) => {
+                InternedString::new("<field>")
+            }
+
+            // note that this does not show up in user printouts
+            CrateRoot => {
+                InternedString::new("<root>")
+            }
+
+            // note that this does not show up in user printouts
+            InlinedRoot(_) => {
+                InternedString::new("<inlined-root>")
+            }
+
+            Misc => {
+                InternedString::new("?")
+            }
+
+            Impl => {
+                InternedString::new("<impl>")
+            }
+
+            ClosureExpr => {
+                InternedString::new("<closure>")
+            }
+
+            StructCtor => {
+                InternedString::new("<constructor>")
+            }
+
+            Initializer => {
+                InternedString::new("<initializer>")
+            }
+        }
+    }
+
+    pub fn to_string(&self) -> String {
+        self.as_interned_str().to_string()
+    }
+}
+
+pub fn make_def_path<FN>(start_index: DefIndex, mut get_key: FN) -> DefPath
+    where FN: FnMut(DefIndex) -> DefKey
+{
+    let mut result = vec![];
+    let mut index = Some(start_index);
+    while let Some(p) = index {
+        let key = get_key(p);
+        match key.disambiguated_data.data {
+            DefPathData::CrateRoot => {
+                assert!(key.parent.is_none());
+                break;
+            }
+            DefPathData::InlinedRoot(ref p) => {
+                assert!(key.parent.is_none());
+                result.extend(p.iter().cloned().rev());
+                break;
+            }
+            _ => {
+                result.push(key.disambiguated_data);
+                index = key.parent;
+            }
+        }
+    }
+    result.reverse();
+    result
+}
diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs
index 16c455537b6..825d5da0c99 100644
--- a/src/librustc/front/map/mod.rs
+++ b/src/librustc/front/map/mod.rs
@@ -11,31 +11,34 @@
 pub use self::Node::*;
 pub use self::PathElem::*;
 use self::MapEntry::*;
+use self::collector::NodeCollector;
+pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
 
 use metadata::inline::InlinedItem;
 use metadata::inline::InlinedItem as II;
 use middle::def_id::DefId;
 
 use syntax::abi;
-use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
+use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
 use syntax::codemap::{Span, Spanned};
 use syntax::parse::token;
 
 use rustc_front::hir::*;
 use rustc_front::fold::Folder;
-use rustc_front::visit::{self, Visitor};
-use rustc_front::util;
+use rustc_front::visit;
 use rustc_front::print::pprust;
 
 use arena::TypedArena;
 use std::cell::RefCell;
 use std::fmt;
 use std::io;
-use std::iter::{self, repeat};
+use std::iter;
 use std::mem;
 use std::slice;
 
 pub mod blocks;
+mod collector;
+pub mod definitions;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub enum PathElem {
@@ -130,7 +133,7 @@ pub enum Node<'ast> {
 /// Represents an entry and its parent NodeID.
 /// The odd layout is to bring down the total size.
 #[derive(Copy, Debug)]
-enum MapEntry<'ast> {
+pub enum MapEntry<'ast> {
     /// Placeholder for holes in the map.
     NotPresent,
 
@@ -263,10 +266,45 @@ pub struct Map<'ast> {
     ///
     /// Also, indexing is pretty quick when you've got a vector and
     /// plain old integers.
-    map: RefCell<Vec<MapEntry<'ast>>>
+    map: RefCell<Vec<MapEntry<'ast>>>,
+
+    definitions: RefCell<Definitions>,
 }
 
 impl<'ast> Map<'ast> {
+    pub fn num_local_def_ids(&self) -> usize {
+        self.definitions.borrow().len()
+    }
+
+    pub fn def_key(&self, def_id: DefId) -> DefKey {
+        assert!(def_id.is_local());
+        self.definitions.borrow().def_key(def_id.index)
+    }
+
+    pub fn def_path_from_id(&self, id: NodeId) -> DefPath {
+        self.def_path(self.local_def_id(id))
+    }
+
+    pub fn def_path(&self, def_id: DefId) -> DefPath {
+        assert!(def_id.is_local());
+        self.definitions.borrow().def_path(def_id.index)
+    }
+
+    pub fn local_def_id(&self, node: NodeId) -> DefId {
+        self.opt_local_def_id(node).unwrap_or_else(|| {
+            panic!("local_def_id: no entry for `{}`, which has a map of `{:?}`",
+                   node, self.find_entry(node))
+        })
+    }
+
+    pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> {
+        self.definitions.borrow().opt_local_def_id(node)
+    }
+
+    pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> {
+        self.definitions.borrow().as_local_node_id(def_id)
+    }
+
     fn entry_count(&self) -> usize {
         self.map.borrow().len()
     }
@@ -288,6 +326,10 @@ impl<'ast> Map<'ast> {
         }
     }
 
+    pub fn get_if_local(&self, id: DefId) -> Option<Node<'ast>> {
+        self.as_local_node_id(id).map(|id| self.get(id))
+    }
+
     /// Retrieve the Node corresponding to `id`, returning None if
     /// cannot be found.
     pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
@@ -383,7 +425,7 @@ impl<'ast> Map<'ast> {
         match self.find_entry(parent) {
             Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did,
             Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did,
-            _ => DefId::local(parent)
+            _ => self.local_def_id(parent)
         }
     }
 
@@ -596,9 +638,13 @@ impl<'ast> Map<'ast> {
             .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id))
     }
 
+    pub fn span_if_local(&self, id: DefId) -> Option<Span> {
+        self.as_local_node_id(id).map(|id| self.span(id))
+    }
+
     pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
-        if def_id.is_local() {
-            self.opt_span(def_id.node).unwrap_or(fallback)
+        if let Some(node_id) = self.as_local_node_id(def_id) {
+            self.opt_span(node_id).unwrap_or(fallback)
         } else {
             fallback
         }
@@ -741,194 +787,10 @@ impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
     }
 }
 
-/// A Visitor that walks over an AST and collects Node's into an AST Map.
-struct NodeCollector<'ast> {
-    map: Vec<MapEntry<'ast>>,
-    parent_node: NodeId,
-}
-
-impl<'ast> NodeCollector<'ast> {
-    fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
-        debug!("ast_map: {:?} => {:?}", id, entry);
-        let len = self.map.len();
-        if id as usize >= len {
-            self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
-        }
-        self.map[id as usize] = entry;
-    }
-
-    fn insert(&mut self, id: NodeId, node: Node<'ast>) {
-        let entry = MapEntry::from_node(self.parent_node, node);
-        self.insert_entry(id, entry);
-    }
-
-    fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
-        for a in &decl.inputs {
-            self.insert(a.id, NodeArg(&*a.pat));
-        }
-    }
-}
-
-impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
-    fn visit_item(&mut self, i: &'ast Item) {
-        self.insert(i.id, NodeItem(i));
-
-        let parent_node = self.parent_node;
-        self.parent_node = i.id;
-
-        match i.node {
-            ItemImpl(_, _, _, _, _, ref impl_items) => {
-                for ii in impl_items {
-                    self.insert(ii.id, NodeImplItem(ii));
-                }
-            }
-            ItemEnum(ref enum_definition, _) => {
-                for v in &enum_definition.variants {
-                    self.insert(v.node.id, NodeVariant(&**v));
-                }
-            }
-            ItemForeignMod(ref nm) => {
-                for nitem in &nm.items {
-                    self.insert(nitem.id, NodeForeignItem(&**nitem));
-                }
-            }
-            ItemStruct(ref struct_def, _) => {
-                // If this is a tuple-like struct, register the constructor.
-                match struct_def.ctor_id {
-                    Some(ctor_id) => {
-                        self.insert(ctor_id, NodeStructCtor(&**struct_def));
-                    }
-                    None => {}
-                }
-            }
-            ItemTrait(_, _, ref bounds, ref trait_items) => {
-                for b in bounds.iter() {
-                    if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
-                        self.insert(t.trait_ref.ref_id, NodeItem(i));
-                    }
-                }
-
-                for ti in trait_items {
-                    self.insert(ti.id, NodeTraitItem(ti));
-                }
-            }
-            ItemUse(ref view_path) => {
-                match view_path.node {
-                    ViewPathList(_, ref paths) => {
-                        for path in paths {
-                            self.insert(path.node.id(), NodeItem(i));
-                        }
-                    }
-                    _ => ()
-                }
-            }
-            _ => {}
-        }
-        visit::walk_item(self, i);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_generics(&mut self, generics: &'ast Generics) {
-        for ty_param in generics.ty_params.iter() {
-            self.insert(ty_param.id, NodeTyParam(ty_param));
-        }
-
-        visit::walk_generics(self, generics);
-    }
-
-    fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
-        let parent_node = self.parent_node;
-        self.parent_node = ti.id;
-        visit::walk_trait_item(self, ti);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
-        let parent_node = self.parent_node;
-        self.parent_node = ii.id;
-
-        visit::walk_impl_item(self, ii);
-
-        self.parent_node = parent_node;
-    }
-
-    fn visit_pat(&mut self, pat: &'ast Pat) {
-        self.insert(pat.id, match pat.node {
-            // Note: this is at least *potentially* a pattern...
-            PatIdent(..) => NodeLocal(pat),
-            _ => NodePat(pat)
-        });
-
-        let parent_node = self.parent_node;
-        self.parent_node = pat.id;
-        visit::walk_pat(self, pat);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_expr(&mut self, expr: &'ast Expr) {
-        self.insert(expr.id, NodeExpr(expr));
-        let parent_node = self.parent_node;
-        self.parent_node = expr.id;
-        visit::walk_expr(self, expr);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_stmt(&mut self, stmt: &'ast Stmt) {
-        let id = util::stmt_id(stmt);
-        self.insert(id, NodeStmt(stmt));
-        let parent_node = self.parent_node;
-        self.parent_node = id;
-        visit::walk_stmt(self, stmt);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: &'ast Block, s: Span, id: NodeId) {
-        let parent_node = self.parent_node;
-        self.parent_node = id;
-        self.visit_fn_decl(fd);
-        visit::walk_fn(self, fk, fd, b, s);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_ty(&mut self, ty: &'ast Ty) {
-        let parent_node = self.parent_node;
-        self.parent_node = ty.id;
-        match ty.node {
-            TyBareFn(ref fd) => {
-                self.visit_fn_decl(&*fd.decl);
-            }
-            _ => {}
-        }
-        visit::walk_ty(self, ty);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_block(&mut self, block: &'ast Block) {
-        self.insert(block.id, NodeBlock(block));
-        let parent_node = self.parent_node;
-        self.parent_node = block.id;
-        visit::walk_block(self, block);
-        self.parent_node = parent_node;
-    }
-
-    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
-        self.insert(lifetime.id, NodeLifetime(lifetime));
-    }
-
-    fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
-        self.visit_lifetime(&def.lifetime);
-    }
-}
-
 pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
-    let mut collector = NodeCollector {
-        map: vec![],
-        parent_node: CRATE_NODE_ID,
-    };
-    collector.insert_entry(CRATE_NODE_ID, RootCrate);
+    let mut collector = NodeCollector::root();
     visit::walk_crate(&mut collector, &forest.krate);
-    let map = collector.map;
+    let NodeCollector { map, definitions, .. } = collector;
 
     if log_enabled!(::log::DEBUG) {
         // This only makes sense for ordered stores; note the
@@ -948,7 +810,8 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
 
     Map {
         forest: forest,
-        map: RefCell::new(map)
+        map: RefCell::new(map),
+        definitions: RefCell::new(definitions),
     }
 }
 
@@ -957,6 +820,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
 /// the item itself.
 pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
                                           path: Vec<PathElem>,
+                                          def_path: DefPath,
                                           ii: InlinedItem,
                                           fold_ops: F)
                                           -> &'ast InlinedItem {
@@ -980,29 +844,18 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
     });
 
     let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
-    let mut collector = NodeCollector {
-        map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
-        parent_node: ii_parent_id,
-    };
-    collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
+    let mut collector =
+        NodeCollector::extend(
+            ii_parent,
+            ii_parent_id,
+            def_path,
+            mem::replace(&mut *map.map.borrow_mut(), vec![]),
+            mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
     ii_parent.ii.visit(&mut collector);
 
-    // Methods get added to the AST map when their impl is visited.  Since we
-    // don't decode and instantiate the impl, but just the method, we have to
-    // add it to the table now. Likewise with foreign items.
-    match ii_parent.ii {
-        II::Item(_) => {}
-        II::TraitItem(_, ref ti) => {
-            collector.insert(ti.id, NodeTraitItem(ti));
-        }
-        II::ImplItem(_, ref ii) => {
-            collector.insert(ii.id, NodeImplItem(ii));
-        }
-        II::Foreign(ref i) => {
-            collector.insert(i.id, NodeForeignItem(i));
-        }
-    }
     *map.map.borrow_mut() = collector.map;
+    *map.definitions.borrow_mut() = collector.definitions;
+
     &ii_parent.ii
 }
 
@@ -1134,3 +987,4 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
     }
 }
+
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 2ffccd2d9a5..85d58924242 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -43,12 +43,16 @@ pub const tag_items_data_parent_item: usize = 0x28;
 
 pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29;
 
+pub const tag_items_closure_kind: usize = 0x2a;
+pub const tag_items_closure_ty: usize = 0x2b;
+pub const tag_def_key: usize = 0x2c;
+
+// GAP 0x2d 0x2e
+
 pub const tag_index: usize = 0x110; // top-level only
 pub const tag_xref_index: usize = 0x111; // top-level only
 pub const tag_xref_data: usize = 0x112; // top-level only
 
-// GAP 0x2a, 0x2b, 0x2c, 0x2d, 0x2e
-
 pub const tag_meta_item_name_value: usize = 0x2f;
 
 pub const tag_meta_item_name: usize = 0x30;
@@ -130,8 +134,7 @@ enum_from_u32! {
         // GAP 0x60
         tag_table_adjustments = 0x61,
         // GAP 0x62, 0x63
-        tag_table_closure_tys = 0x64,
-        tag_table_closure_kinds = 0x65,
+            // GAP 0x64, 0x65
         tag_table_upvar_capture_map = 0x66,
         // GAP 0x67, 0x68
         tag_table_const_qualif = 0x69,
@@ -150,12 +153,12 @@ pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only
 // tag_lang_items
 // - tag_lang_items_item
 //   - tag_lang_items_item_id: u32
-//   - tag_lang_items_item_node_id: u32
+//   - tag_lang_items_item_index: u32
 
 pub const tag_lang_items: usize = 0x107; // top-level only
 pub const tag_lang_items_item: usize = 0x73;
 pub const tag_lang_items_item_id: usize = 0x74;
-pub const tag_lang_items_item_node_id: usize = 0x75;
+pub const tag_lang_items_item_index: usize = 0x75;
 pub const tag_lang_items_missing: usize = 0x76;
 
 pub const tag_item_unnamed_field: usize = 0x77;
@@ -202,8 +205,8 @@ pub struct LinkMeta {
 
 pub const tag_struct_fields: usize = 0x10d; // top-level only
 pub const tag_struct_field: usize = 0x8a;
-pub const tag_struct_field_id: usize = 0x8b;
 
+pub const tag_items_data_item_struct_ctor: usize = 0x8b;
 pub const tag_attribute_is_sugared_doc: usize = 0x8c;
 
 pub const tag_items_data_region: usize = 0x8e;
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index c40eb56917d..6c81562f7b2 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -325,6 +325,7 @@ impl<'a> CrateReader<'a> {
         let cmeta = Rc::new(cstore::crate_metadata {
             name: name.to_string(),
             local_path: RefCell::new(SmallVector::zero()),
+            local_def_path: RefCell::new(vec![]),
             index: decoder::load_index(metadata.as_slice()),
             xref_index: decoder::load_xrefs(metadata.as_slice()),
             data: metadata,
@@ -549,7 +550,8 @@ impl<'a> CrateReader<'a> {
             self.sess.abort_if_errors();
         }
 
-        let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
+        let registrar =
+            decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
             .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id));
 
         match (ekrate.dylib.as_ref(), registrar) {
@@ -752,6 +754,9 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
                                                               i.span,
                                                               PathKind::Crate,
                                                               true);
+                        let def_id = self.ast_map.local_def_id(i.id);
+                        let def_path = self.ast_map.def_path(def_id);
+                        cmeta.update_local_def_path(def_path);
                         self.ast_map.with_path(i.id, |path| {
                             cmeta.update_local_path(path)
                         });
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index dd6250d92aa..e04df51dc68 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -14,7 +14,7 @@ use front::map as ast_map;
 use metadata::cstore;
 use metadata::decoder;
 use metadata::inline::InlinedItem;
-use middle::def_id::DefId;
+use middle::def_id::{DefId, DefIndex};
 use middle::lang_items;
 use middle::ty;
 use util::nodemap::FnvHashMap;
@@ -33,7 +33,7 @@ pub struct MethodInfo {
 
 pub fn get_symbol(cstore: &cstore::CStore, def: DefId) -> String {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_symbol(&cdata, def.node)
+    decoder::get_symbol(&cdata, def.index)
 }
 
 /// Iterates over all the language items in the given crate.
@@ -41,7 +41,7 @@ pub fn each_lang_item<F>(cstore: &cstore::CStore,
                          cnum: ast::CrateNum,
                          f: F)
                          -> bool where
-    F: FnMut(ast::NodeId, usize) -> bool,
+    F: FnMut(DefIndex, usize) -> bool,
 {
     let crate_data = cstore.get_crate_data(cnum);
     decoder::each_lang_item(&*crate_data, f)
@@ -59,7 +59,7 @@ pub fn each_child_of_item<F>(cstore: &cstore::CStore,
     };
     decoder::each_child_of_item(cstore.intr.clone(),
                                 &*crate_data,
-                                def_id.node,
+                                def_id.index,
                                 get_crate_data,
                                 callback)
 }
@@ -83,7 +83,7 @@ pub fn each_top_level_item_of_crate<F>(cstore: &cstore::CStore,
 pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec<ast_map::PathElem> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    let path = decoder::get_item_path(&*cdata, def.node);
+    let path = decoder::get_item_path(&*cdata, def.index);
 
     cdata.with_local_path(|cpath| {
         let mut r = Vec::with_capacity(cpath.len() + path.len());
@@ -96,7 +96,7 @@ pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec<ast_map::PathElem> {
 pub fn get_item_name(tcx: &ty::ctxt, def: DefId) -> ast::Name {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_item_name(&cstore.intr, &cdata, def.node)
+    decoder::get_item_name(&cstore.intr, &cdata, def.index)
 }
 
 pub enum FoundAst<'ast> {
@@ -113,14 +113,14 @@ pub fn maybe_get_item_ast<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId,
                                 -> FoundAst<'tcx> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::maybe_get_item_ast(&*cdata, tcx, def.node, decode_inlined_item)
+    decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item)
 }
 
 /// Returns information about the given implementation.
 pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: DefId)
                       -> Vec<ty::ImplOrTraitItemId> {
     let cdata = cstore.get_crate_data(impl_def_id.krate);
-    decoder::get_impl_items(&*cdata, impl_def_id.node)
+    decoder::get_impl_items(&*cdata, impl_def_id.index)
 }
 
 pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
@@ -128,7 +128,7 @@ pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
     let cdata = tcx.sess.cstore.get_crate_data(def.krate);
     decoder::get_impl_or_trait_item(tcx.sess.cstore.intr.clone(),
                                     &*cdata,
-                                    def.node,
+                                    def.index,
                                     tcx)
 }
 
@@ -136,24 +136,24 @@ pub fn get_trait_name(cstore: &cstore::CStore, def: DefId) -> ast::Name {
     let cdata = cstore.get_crate_data(def.krate);
     decoder::get_trait_name(cstore.intr.clone(),
                             &*cdata,
-                            def.node)
+                            def.index)
 }
 
 pub fn is_static_method(cstore: &cstore::CStore, def: DefId) -> bool {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::is_static_method(&*cdata, def.node)
+    decoder::is_static_method(&*cdata, def.index)
 }
 
 pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: DefId)
                               -> Vec<ty::ImplOrTraitItemId> {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_trait_item_def_ids(&*cdata, def.node)
+    decoder::get_trait_item_def_ids(&*cdata, def.index)
 }
 
 pub fn get_item_variances(cstore: &cstore::CStore,
                           def: DefId) -> ty::ItemVariances {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_item_variances(&*cdata, def.node)
+    decoder::get_item_variances(&*cdata, def.index)
 }
 
 pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
@@ -161,37 +161,37 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
                                         -> Vec<Rc<ty::Method<'tcx>>> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
+    decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.index, tcx)
 }
 
 pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
                                    -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
+    decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.index, tcx)
 }
 
 pub fn get_methods_if_impl(cstore: &cstore::CStore,
                                   def: DefId)
                                -> Option<Vec<MethodInfo> > {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.node)
+    decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.index)
 }
 
 pub fn get_item_attrs(cstore: &cstore::CStore,
                       def_id: DefId)
                       -> Vec<ast::Attribute> {
     let cdata = cstore.get_crate_data(def_id.krate);
-    decoder::get_item_attrs(&*cdata, def_id.node)
+    decoder::get_item_attrs(&*cdata, def_id.index)
 }
 
 pub fn get_struct_field_names(cstore: &cstore::CStore, def: DefId) -> Vec<ast::Name> {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_struct_field_names(&cstore.intr, &*cdata, def.node)
+    decoder::get_struct_field_names(&cstore.intr, &*cdata, def.index)
 }
 
-pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId) -> FnvHashMap<ast::NodeId,
-        Vec<ast::Attribute>> {
+pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId)
+                              -> FnvHashMap<DefId, Vec<ast::Attribute>> {
     let cdata = cstore.get_crate_data(def.krate);
     decoder::get_struct_field_attrs(&*cdata)
 }
@@ -201,19 +201,19 @@ pub fn get_type<'tcx>(tcx: &ty::ctxt<'tcx>,
                       -> ty::TypeScheme<'tcx> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_type(&*cdata, def.node, tcx)
+    decoder::get_type(&*cdata, def.index, tcx)
 }
 
 pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_trait_def(&*cdata, def.node, tcx)
+    decoder::get_trait_def(&*cdata, def.index, tcx)
 }
 
 pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx)
+    decoder::get_adt_def(&cstore.intr, &*cdata, def.index, tcx)
 }
 
 pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
@@ -221,7 +221,7 @@ pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
 {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_predicates(&*cdata, def.node, tcx)
+    decoder::get_predicates(&*cdata, def.index, tcx)
 }
 
 pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
@@ -229,7 +229,7 @@ pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
 {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_super_predicates(&*cdata, def.node, tcx)
+    decoder::get_super_predicates(&*cdata, def.index, tcx)
 }
 
 pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
@@ -238,7 +238,7 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
 {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_impl_polarity(&*cdata, def.node)
+    decoder::get_impl_polarity(&*cdata, def.index)
 }
 
 pub fn get_custom_coerce_unsized_kind<'tcx>(
@@ -248,7 +248,7 @@ pub fn get_custom_coerce_unsized_kind<'tcx>(
 {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
+    decoder::get_custom_coerce_unsized_kind(&*cdata, def.index)
 }
 
 // Given a def_id for an impl, return the trait it implements,
@@ -258,7 +258,7 @@ pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
                             -> Option<ty::TraitRef<'tcx>> {
     let cstore = &tcx.sess.cstore;
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_impl_trait(&*cdata, def.node, tcx)
+    decoder::get_impl_trait(&*cdata, def.index, tcx)
 }
 
 pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum)
@@ -273,7 +273,7 @@ pub fn each_inherent_implementation_for_type<F>(cstore: &cstore::CStore,
     F: FnMut(DefId),
 {
     let cdata = cstore.get_crate_data(def_id.krate);
-    decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback)
+    decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, callback)
 }
 
 pub fn each_implementation_for_trait<F>(cstore: &cstore::CStore,
@@ -294,7 +294,7 @@ pub fn get_trait_of_item(cstore: &cstore::CStore,
                          tcx: &ty::ctxt)
                          -> Option<DefId> {
     let cdata = cstore.get_crate_data(def_id.krate);
-    decoder::get_trait_of_item(&*cdata, def_id.node, tcx)
+    decoder::get_trait_of_item(&*cdata, def_id.index, tcx)
 }
 
 pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
@@ -302,7 +302,7 @@ pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
     -> Option<DefId>
 {
     let cdata = cstore.get_crate_data(def_id.krate);
-    decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.node)
+    decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.index)
 }
 
 pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
@@ -324,7 +324,7 @@ pub fn get_method_arg_names(cstore: &cstore::CStore, did: DefId)
     -> Vec<String>
 {
     let cdata = cstore.get_crate_data(did.krate);
-    decoder::get_method_arg_names(&*cdata, did.node)
+    decoder::get_method_arg_names(&*cdata, did.index)
 }
 
 pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum)
@@ -336,24 +336,24 @@ pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum)
 
 pub fn is_typedef(cstore: &cstore::CStore, did: DefId) -> bool {
     let cdata = cstore.get_crate_data(did.krate);
-    decoder::is_typedef(&*cdata, did.node)
+    decoder::is_typedef(&*cdata, did.index)
 }
 
 pub fn is_const_fn(cstore: &cstore::CStore, did: DefId) -> bool {
     let cdata = cstore.get_crate_data(did.krate);
-    decoder::is_const_fn(&*cdata, did.node)
+    decoder::is_const_fn(&*cdata, did.index)
 }
 
 pub fn is_impl(cstore: &cstore::CStore, did: DefId) -> bool {
     let cdata = cstore.get_crate_data(did.krate);
-    decoder::is_impl(&*cdata, did.node)
+    decoder::is_impl(&*cdata, did.index)
 }
 
 pub fn get_stability(cstore: &cstore::CStore,
                      def: DefId)
                      -> Option<attr::Stability> {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_stability(&*cdata, def.node)
+    decoder::get_stability(&*cdata, def.index)
 }
 
 pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool {
@@ -363,21 +363,42 @@ pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool {
 pub fn get_repr_attrs(cstore: &cstore::CStore, def: DefId)
                       -> Vec<attr::ReprAttr> {
     let cdata = cstore.get_crate_data(def.krate);
-    decoder::get_repr_attrs(&*cdata, def.node)
+    decoder::get_repr_attrs(&*cdata, def.index)
 }
 
 pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: DefId) -> bool {
     let cdata = cstore.get_crate_data(trait_def_id.krate);
-    decoder::is_defaulted_trait(&*cdata, trait_def_id.node)
+    decoder::is_defaulted_trait(&*cdata, trait_def_id.index)
 }
 
 pub fn is_default_impl(cstore: &cstore::CStore, impl_did: DefId) -> bool {
     let cdata = cstore.get_crate_data(impl_did.krate);
-    decoder::is_default_impl(&*cdata, impl_did.node)
+    decoder::is_default_impl(&*cdata, impl_did.index)
 }
 
 pub fn is_extern_fn(cstore: &cstore::CStore, did: DefId,
                     tcx: &ty::ctxt) -> bool {
     let cdata = cstore.get_crate_data(did.krate);
-    decoder::is_extern_fn(&*cdata, did.node, tcx)
+    decoder::is_extern_fn(&*cdata, did.index, tcx)
 }
+
+pub fn closure_kind<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind {
+    assert!(!def_id.is_local());
+    let cdata = tcx.sess.cstore.get_crate_data(def_id.krate);
+    decoder::closure_kind(&*cdata, def_id.index)
+}
+
+pub fn closure_ty<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
+    assert!(!def_id.is_local());
+    let cdata = tcx.sess.cstore.get_crate_data(def_id.krate);
+    decoder::closure_ty(&*cdata, def_id.index, tcx)
+}
+
+pub fn def_path(tcx: &ty::ctxt, def: DefId) -> ast_map::DefPath {
+    let cstore = &tcx.sess.cstore;
+    let cdata = cstore.get_crate_data(def.krate);
+    let path = decoder::def_path(&*cdata, def.index);
+    let local_path = cdata.local_def_path();
+    local_path.into_iter().chain(path).collect()
+}
+
diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs
index 9ffe8cd1d11..c0e7667666c 100644
--- a/src/librustc/metadata/cstore.rs
+++ b/src/librustc/metadata/cstore.rs
@@ -59,6 +59,7 @@ pub struct ImportedFileMap {
 pub struct crate_metadata {
     pub name: String,
     pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
+    pub local_def_path: RefCell<ast_map::DefPath>,
     pub data: MetadataBlob,
     pub cnum_map: RefCell<cnum_map>,
     pub cnum: ast::CrateNum,
@@ -111,6 +112,10 @@ pub struct CStore {
     pub intr: Rc<IdentInterner>,
 }
 
+/// Item definitions in the currently-compiled crate would have the CrateNum
+/// LOCAL_CRATE in their DefId.
+pub const LOCAL_CRATE: ast::CrateNum = 0;
+
 impl CStore {
     pub fn new(intr: Rc<IdentInterner>) -> CStore {
         CStore {
@@ -310,6 +315,23 @@ impl crate_metadata {
         }
     }
 
+    pub fn local_def_path(&self) -> ast_map::DefPath {
+        let local_def_path = self.local_def_path.borrow();
+        if local_def_path.is_empty() {
+            let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name));
+            vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }]
+        } else {
+            local_def_path.clone()
+        }
+    }
+
+    pub fn update_local_def_path(&self, candidate: ast_map::DefPath) {
+        let mut local_def_path = self.local_def_path.borrow_mut();
+        if local_def_path.is_empty() || candidate.len() < local_def_path.len() {
+            *local_def_path = candidate;
+        }
+    }
+
     pub fn is_allocator(&self) -> bool {
         let attrs = decoder::get_crate_attributes(self.data());
         attr::contains_name(&attrs, "allocator")
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 69d3e55835f..28d801bb8c9 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -15,11 +15,12 @@
 pub use self::DefLike::*;
 use self::Family::*;
 
-use front::map as ast_map;
+use front::map as hir_map;
 use rustc_front::hir;
 
 use back::svh::Svh;
 use metadata::cstore::crate_metadata;
+use metadata::cstore::LOCAL_CRATE;
 use metadata::common::*;
 use metadata::csearch::MethodInfo;
 use metadata::csearch;
@@ -29,7 +30,7 @@ use metadata::index;
 use metadata::inline::InlinedItem;
 use metadata::tydecode::TyDecoder;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{DefId, DefIndex};
 use middle::lang_items;
 use middle::subst;
 use middle::ty::{ImplContainer, TraitContainer};
@@ -58,15 +59,15 @@ use syntax::ptr::P;
 pub type Cmd<'a> = &'a crate_metadata;
 
 impl crate_metadata {
-    fn get_item(&self, item_id: ast::NodeId) -> Option<rbml::Doc> {
+    fn get_item(&self, item_id: DefIndex) -> Option<rbml::Doc> {
         self.index.lookup_item(self.data(), item_id).map(|pos| {
             reader::doc_at(self.data(), pos as usize).unwrap().doc
         })
     }
 
-    fn lookup_item(&self, item_id: ast::NodeId) -> rbml::Doc {
+    fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
         match self.get_item(item_id) {
-            None => panic!("lookup_item: id not found: {}", item_id),
+            None => panic!("lookup_item: id not found: {:?}", item_id),
             Some(d) => d
         }
     }
@@ -74,7 +75,7 @@ impl crate_metadata {
 
 pub fn load_index(data: &[u8]) -> index::Index {
     let index = reader::get_doc(rbml::Doc::new(data), tag_index);
-    index::Index::from_buf(index.data, index.start, index.end)
+    index::Index::from_rbml(index)
 }
 
 pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
@@ -174,7 +175,8 @@ fn item_symbol(item: rbml::Doc) -> String {
 
 fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
     let id = reader::doc_as_u64(d);
-    let def_id = DefId { krate: (id >> 32) as u32, node: id as u32 };
+    let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
+    let def_id = DefId { krate: (id >> 32) as u32, index: index };
     translate_def_id(cdata, def_id)
 }
 
@@ -207,14 +209,14 @@ fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
 fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> {
     let tp = reader::get_doc(doc, tag_items_data_item_type);
     TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                        &mut |_, did| translate_def_id(cdata, did))
+                        &mut |did| translate_def_id(cdata, did))
         .parse_ty()
 }
 
 fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
     reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
         TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                            &mut |_, did| translate_def_id(cdata, did))
+                            &mut |did| translate_def_id(cdata, did))
             .parse_ty()
     })
 }
@@ -227,7 +229,7 @@ pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc,
 fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
                        -> ty::TraitRef<'tcx> {
     TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                        &mut |_, did| translate_def_id(cdata, did))
+                        &mut |did| translate_def_id(cdata, did))
         .parse_trait_ref()
 }
 
@@ -237,15 +239,15 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
     doc_trait_ref(tp, tcx, cdata)
 }
 
-fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
+fn item_path(item_doc: rbml::Doc) -> Vec<hir_map::PathElem> {
     let path_doc = reader::get_doc(item_doc, tag_path);
     reader::docs(path_doc).filter_map(|(tag, elt_doc)| {
         if tag == tag_path_elem_mod {
             let s = elt_doc.as_str_slice();
-            Some(ast_map::PathMod(token::intern(s)))
+            Some(hir_map::PathMod(token::intern(s)))
         } else if tag == tag_path_elem_name {
             let s = elt_doc.as_str_slice();
-            Some(ast_map::PathName(token::intern(s)))
+            Some(hir_map::PathName(token::intern(s)))
         } else {
             // ignore tag_path_len element
             None
@@ -341,7 +343,7 @@ fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
 }
 
 pub fn get_trait_def<'tcx>(cdata: Cmd,
-                           item_id: ast::NodeId,
+                           item_id: DefIndex,
                            tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
 {
     let item_doc = cdata.lookup_item(item_id);
@@ -364,7 +366,7 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
 
 pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                          cdata: Cmd,
-                         item_id: ast::NodeId,
+                         item_id: DefIndex,
                          tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
 {
     fn get_enum_variants<'tcx>(intr: &IdentInterner,
@@ -374,7 +376,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
         let mut disr_val = 0;
         reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
             let did = translated_def_id(cdata, p);
-            let item = cdata.lookup_item(did.node);
+            let item = cdata.lookup_item(did.index);
 
             if let Some(disr) = variant_disr_val(item) {
                 disr_val = disr;
@@ -386,6 +388,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                 did: did,
                 name: item_name(intr, item),
                 fields: get_variant_fields(intr, cdata, item, tcx),
+                ctor_id: did,
                 disr_val: disr
             }
         }).collect()
@@ -414,23 +417,34 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                                 cdata: Cmd,
                                 doc: rbml::Doc,
                                 did: DefId,
+                                ctor_id: DefId,
                                 tcx: &ty::ctxt<'tcx>) -> ty::VariantDefData<'tcx, 'tcx> {
         ty::VariantDefData {
             did: did,
             name: item_name(intr, doc),
             fields: get_variant_fields(intr, cdata, doc, tcx),
+            ctor_id: ctor_id,
             disr_val: 0
         }
     }
 
     let doc = cdata.lookup_item(item_id);
-    let did = DefId { krate: cdata.cnum, node: item_id };
+    let did = DefId { krate: cdata.cnum, index: item_id };
     let (kind, variants) = match item_family(doc) {
-        Enum => (ty::AdtKind::Enum,
-                 get_enum_variants(intr, cdata, doc, tcx)),
-        Struct => (ty::AdtKind::Struct,
-                   vec![get_struct_variant(intr, cdata, doc, did, tcx)]),
-        _ => tcx.sess.bug("get_adt_def called on a non-ADT")
+        Enum => {
+            (ty::AdtKind::Enum,
+             get_enum_variants(intr, cdata, doc, tcx))
+        }
+        Struct => {
+            let ctor_did =
+                reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
+                map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
+            (ty::AdtKind::Struct,
+             vec![get_struct_variant(intr, cdata, doc, did, ctor_did, tcx)])
+        }
+        _ => tcx.sess.bug(
+            &format!("get_adt_def called on a non-ADT {:?} - {:?}",
+                     item_family(doc), did))
     };
 
     let adt = tcx.intern_adt_def(did, kind, variants);
@@ -444,7 +458,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
             // from the ctor.
             debug!("evaluating the ctor-type of {:?}",
                    variant.name);
-            let ctor_ty = get_type(cdata, variant.did.node, tcx).ty;
+            let ctor_ty = get_type(cdata, variant.did.index, tcx).ty;
             debug!("evaluating the ctor-type of {:?}.. {:?}",
                    variant.name,
                    ctor_ty);
@@ -464,7 +478,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
         } else {
             for field in &variant.fields {
                 debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
-                let ty = get_type(cdata, field.did.node, tcx).ty;
+                let ty = get_type(cdata, field.did.index, tcx).ty;
                 field.fulfill_ty(ty);
                 debug!("evaluating the type of {:?}::{:?}: {:?}",
                        variant.name, field.name, ty);
@@ -476,7 +490,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
 }
 
 pub fn get_predicates<'tcx>(cdata: Cmd,
-                            item_id: ast::NodeId,
+                            item_id: DefIndex,
                             tcx: &ty::ctxt<'tcx>)
                             -> ty::GenericPredicates<'tcx>
 {
@@ -485,7 +499,7 @@ pub fn get_predicates<'tcx>(cdata: Cmd,
 }
 
 pub fn get_super_predicates<'tcx>(cdata: Cmd,
-                                  item_id: ast::NodeId,
+                                  item_id: DefIndex,
                                   tcx: &ty::ctxt<'tcx>)
                                   -> ty::GenericPredicates<'tcx>
 {
@@ -493,11 +507,11 @@ pub fn get_super_predicates<'tcx>(cdata: Cmd,
     doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
 }
 
-pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
+pub fn get_type<'tcx>(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt<'tcx>)
                       -> ty::TypeScheme<'tcx>
 {
     let item_doc = cdata.lookup_item(id);
-    let t = item_type(DefId { krate: cdata.cnum, node: id }, item_doc, tcx,
+    let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx,
                       cdata);
     let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
     ty::TypeScheme {
@@ -506,7 +520,7 @@ pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
     }
 }
 
-pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
+pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
     let item = cdata.lookup_item(id);
     reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
         let mut decoder = reader::Decoder::new(doc);
@@ -514,7 +528,7 @@ pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
     })
 }
 
-pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
+pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
     let item = cdata.lookup_item(id);
     match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
         let mut decoder = reader::Decoder::new(doc);
@@ -526,7 +540,7 @@ pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
 }
 
 pub fn get_impl_polarity<'tcx>(cdata: Cmd,
-                               id: ast::NodeId)
+                               id: DefIndex)
                                -> Option<hir::ImplPolarity>
 {
     let item_doc = cdata.lookup_item(id);
@@ -541,7 +555,7 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd,
 
 pub fn get_custom_coerce_unsized_kind<'tcx>(
     cdata: Cmd,
-    id: ast::NodeId)
+    id: DefIndex)
     -> Option<ty::adjustment::CustomCoerceUnsized>
 {
     let item_doc = cdata.lookup_item(id);
@@ -552,7 +566,7 @@ pub fn get_custom_coerce_unsized_kind<'tcx>(
 }
 
 pub fn get_impl_trait<'tcx>(cdata: Cmd,
-                            id: ast::NodeId,
+                            id: DefIndex,
                             tcx: &ty::ctxt<'tcx>)
                             -> Option<ty::TraitRef<'tcx>>
 {
@@ -568,12 +582,12 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd,
     }
 }
 
-pub fn get_symbol(cdata: Cmd, id: ast::NodeId) -> String {
+pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String {
     return item_symbol(cdata.lookup_item(id));
 }
 
 /// If you have a crate_metadata, call get_symbol instead
-pub fn get_symbol_from_buf(data: &[u8], id: ast::NodeId) -> String {
+pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String {
     let index = load_index(data);
     let pos = index.lookup_item(data, id).unwrap();
     let doc = reader::doc_at(data, pos as usize).unwrap().doc;
@@ -590,18 +604,17 @@ pub enum DefLike {
 
 /// Iterates over the language items in the given crate.
 pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
-    F: FnMut(ast::NodeId, usize) -> bool,
+    F: FnMut(DefIndex, usize) -> bool,
 {
     let root = rbml::Doc::new(cdata.data());
     let lang_items = reader::get_doc(root, tag_lang_items);
     reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
         let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
         let id = reader::doc_as_u32(id_doc) as usize;
-        let node_id_doc = reader::get_doc(item_doc,
-                                          tag_lang_items_item_node_id);
-        let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId;
+        let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index);
+        let index = DefIndex::from_u32(reader::doc_as_u32(index_doc));
 
-        f(node_id, id)
+        f(index, id)
     })
 }
 
@@ -630,7 +643,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
         };
 
         // Get the item.
-        match crate_data.get_item(child_def_id.node) {
+        match crate_data.get_item(child_def_id.index) {
             None => {}
             Some(child_item_doc) => {
                 // Hand off the item to the callback.
@@ -648,12 +661,12 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
     for inherent_impl_def_id_doc in reader::tagged_docs(item_doc,
                                                              tag_items_data_item_inherent_impl) {
         let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata);
-        if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.node) {
+        if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) {
             for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc,
                                                                  tag_item_impl_item) {
                 let impl_item_def_id = item_def_id(impl_item_def_id_doc,
                                                    cdata);
-                if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.node) {
+                if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) {
                     if let StaticMethod = item_family(impl_method_doc) {
                         // Hand off the static method to the callback.
                         let static_method_name = item_name(&*intr, impl_method_doc);
@@ -689,7 +702,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
         };
 
         // Get the item.
-        if let Some(child_item_doc) = crate_data.get_item(child_def_id.node) {
+        if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
             // Hand off the item to the callback.
             let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
             // These items have a public visibility because they're part of
@@ -702,7 +715,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
 /// Iterates over each child of the given item.
 pub fn each_child_of_item<F, G>(intr: Rc<IdentInterner>,
                                cdata: Cmd,
-                               id: ast::NodeId,
+                               id: DefIndex,
                                get_crate_data: G,
                                callback: F) where
     F: FnMut(DefLike, ast::Name, hir::Visibility),
@@ -741,34 +754,39 @@ pub fn each_top_level_item_of_crate<F, G>(intr: Rc<IdentInterner>,
                                 callback)
 }
 
-pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec<ast_map::PathElem> {
+pub fn get_item_path(cdata: Cmd, id: DefIndex) -> Vec<hir_map::PathElem> {
     item_path(cdata.lookup_item(id))
 }
 
-pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) -> ast::Name {
+pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Name {
     item_name(intr, cdata.lookup_item(id))
 }
 
 pub type DecodeInlinedItem<'a> =
     Box<for<'tcx> FnMut(Cmd,
                         &ty::ctxt<'tcx>,
-                        Vec<ast_map::PathElem>,
-                        rbml::Doc)
-                        -> Result<&'tcx InlinedItem, Vec<ast_map::PathElem>> + 'a>;
-
-pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId,
+                        Vec<hir_map::PathElem>,
+                        hir_map::DefPath,
+                        rbml::Doc,
+                        DefId)
+                        -> Result<&'tcx InlinedItem, (Vec<hir_map::PathElem>,
+                                                      hir_map::DefPath)> + 'a>;
+
+pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex,
                                 mut decode_inlined_item: DecodeInlinedItem)
                                 -> csearch::FoundAst<'tcx> {
-    debug!("Looking up item: {}", id);
+    debug!("Looking up item: {:?}", id);
     let item_doc = cdata.lookup_item(id);
+    let item_did = item_def_id(item_doc, cdata);
     let path = item_path(item_doc).split_last().unwrap().1.to_vec();
-    match decode_inlined_item(cdata, tcx, path, item_doc) {
+    let def_path = def_path(cdata, id);
+    match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) {
         Ok(ii) => csearch::FoundAst::Found(ii),
-        Err(path) => {
+        Err((path, def_path)) => {
             match item_parent_item(cdata, item_doc) {
                 Some(did) => {
-                    let parent_item = cdata.lookup_item(did.node);
-                    match decode_inlined_item(cdata, tcx, path, parent_item) {
+                    let parent_item = cdata.lookup_item(did.index);
+                    match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) {
                         Ok(ii) => csearch::FoundAst::FoundParent(did, ii),
                         Err(_) => csearch::FoundAst::NotFound
                     }
@@ -807,7 +825,7 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
 }
 
 /// Returns the def IDs of all the items in the given implementation.
-pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
+pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex)
                       -> Vec<ty::ImplOrTraitItemId> {
     reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| {
         let def_id = item_def_id(doc, cdata);
@@ -822,13 +840,13 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
 
 pub fn get_trait_name(intr: Rc<IdentInterner>,
                       cdata: Cmd,
-                      id: ast::NodeId)
+                      id: DefIndex)
                       -> ast::Name {
     let doc = cdata.lookup_item(id);
     item_name(&*intr, doc)
 }
 
-pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool {
     let doc = cdata.lookup_item(id);
     match item_sort(doc) {
         Some('r') | Some('p') => {
@@ -840,7 +858,7 @@ pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool {
 
 pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                                     cdata: Cmd,
-                                    id: ast::NodeId,
+                                    id: DefIndex,
                                     tcx: &ty::ctxt<'tcx>)
                                     -> ty::ImplOrTraitItem<'tcx> {
     let item_doc = cdata.lookup_item(id);
@@ -848,7 +866,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
     let def_id = item_def_id(item_doc, cdata);
 
     let container_id = item_require_parent_item(cdata, item_doc);
-    let container_doc = cdata.lookup_item(container_id.node);
+    let container_doc = cdata.lookup_item(container_id.index);
     let container = match item_family(container_doc) {
         Trait => TraitContainer(container_id),
         _ => ImplContainer(container_id),
@@ -904,7 +922,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
     }
 }
 
-pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
+pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex)
                               -> Vec<ty::ImplOrTraitItemId> {
     let item = cdata.lookup_item(id);
     reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
@@ -918,7 +936,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
     }).collect()
 }
 
-pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
+pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances {
     let item_doc = cdata.lookup_item(id);
     let variance_doc = reader::get_doc(item_doc, tag_item_variances);
     let mut decoder = reader::Decoder::new(variance_doc);
@@ -927,19 +945,19 @@ pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
 
 pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
                                         cdata: Cmd,
-                                        id: ast::NodeId,
+                                        id: DefIndex,
                                         tcx: &ty::ctxt<'tcx>)
                                         -> Vec<Rc<ty::Method<'tcx>>> {
     let item = cdata.lookup_item(id);
 
     reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
         let did = item_def_id(mth_id, cdata);
-        let mth = cdata.lookup_item(did.node);
+        let mth = cdata.lookup_item(did.index);
 
         if item_sort(mth) == Some('p') {
             let trait_item = get_impl_or_trait_item(intr.clone(),
                                                     cdata,
-                                                    did.node,
+                                                    did.index,
                                                     tcx);
             if let ty::MethodTraitItem(ref method) = trait_item {
                 Some((*method).clone())
@@ -954,7 +972,7 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
 
 pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
                                    cdata: Cmd,
-                                   id: ast::NodeId,
+                                   id: DefIndex,
                                    tcx: &ty::ctxt<'tcx>)
                                    -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
     let item = cdata.lookup_item(id);
@@ -962,13 +980,13 @@ pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
     [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
         reader::tagged_docs(item, tag).filter_map(|ac_id| {
             let did = item_def_id(ac_id, cdata);
-            let ac_doc = cdata.lookup_item(did.node);
+            let ac_doc = cdata.lookup_item(did.index);
 
             match item_sort(ac_doc) {
                 Some('C') | Some('c') => {
                     let trait_item = get_impl_or_trait_item(intr.clone(),
                                                             cdata,
-                                                            did.node,
+                                                            did.index,
                                                             tcx);
                     if let ty::ConstTraitItem(ref ac) = trait_item {
                         Some((*ac).clone())
@@ -984,7 +1002,7 @@ pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
 
 pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
                                   cdata: Cmd,
-                                  node_id: ast::NodeId)
+                                  node_id: DefIndex)
                                -> Option<Vec<MethodInfo> > {
     let item = cdata.lookup_item(node_id);
     if item_family(item) != Impl {
@@ -1001,7 +1019,7 @@ pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
 
     let mut impl_methods = Vec::new();
     for impl_method_id in impl_method_ids {
-        let impl_method_doc = cdata.lookup_item(impl_method_id.node);
+        let impl_method_doc = cdata.lookup_item(impl_method_id.index);
         let family = item_family(impl_method_doc);
         match family {
             StaticMethod | Method => {
@@ -1021,7 +1039,7 @@ pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
 /// If node_id is the constructor of a tuple struct, retrieve the NodeId of
 /// the actual type definition, otherwise, return None
 pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
-                                           node_id: ast::NodeId)
+                                           node_id: DefIndex)
     -> Option<DefId>
 {
     let item = cdata.lookup_item(node_id);
@@ -1031,24 +1049,24 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
 }
 
 pub fn get_item_attrs(cdata: Cmd,
-                      orig_node_id: ast::NodeId)
+                      orig_node_id: DefIndex)
                       -> Vec<ast::Attribute> {
     // The attributes for a tuple struct are attached to the definition, not the ctor;
     // we assume that someone passing in a tuple struct ctor is actually wanting to
     // look at the definition
     let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
-    let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id);
+    let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id);
     let item = cdata.lookup_item(node_id);
     get_attributes(item)
 }
 
-pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<ast::NodeId, Vec<ast::Attribute>> {
+pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<DefId, Vec<ast::Attribute>> {
     let data = rbml::Doc::new(cdata.data());
     let fields = reader::get_doc(data, tag_struct_fields);
     reader::tagged_docs(fields, tag_struct_field).map(|field| {
-        let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id));
+        let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id));
         let attrs = get_attributes(field);
-        (id, attrs)
+        (def_id, attrs)
     }).collect()
 }
 
@@ -1060,7 +1078,7 @@ fn struct_field_family_to_visibility(family: Family) -> hir::Visibility {
     }
 }
 
-pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId)
+pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: DefIndex)
     -> Vec<ast::Name> {
     let item = cdata.lookup_item(id);
     reader::tagged_docs(item, tag_item_field).map(|an_item| {
@@ -1218,14 +1236,14 @@ pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()>
 // crate to the correct local crate number.
 pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
     if did.is_local() {
-        return DefId { krate: cdata.cnum, node: did.node };
+        return DefId { krate: cdata.cnum, index: did.index };
     }
 
     match cdata.cnum_map.borrow().get(&did.krate) {
         Some(&n) => {
             DefId {
                 krate: n,
-                node: did.node,
+                index: did.index,
             }
         }
         None => panic!("didn't find a crate in the cnum_map")
@@ -1236,12 +1254,12 @@ pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
 // for an external crate.
 fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
     if did.krate == cdata.cnum {
-        return Some(DefId { krate: LOCAL_CRATE, node: did.node });
+        return Some(DefId { krate: LOCAL_CRATE, index: did.index });
     }
 
     for (&local, &global) in cdata.cnum_map.borrow().iter() {
         if global == did.krate {
-            return Some(DefId { krate: local, node: did.node });
+            return Some(DefId { krate: local, index: did.index });
         }
     }
 
@@ -1249,7 +1267,7 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
 }
 
 pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
-                                                id: ast::NodeId,
+                                                id: DefIndex,
                                                 mut callback: F)
     where F: FnMut(DefId),
 {
@@ -1267,7 +1285,7 @@ pub fn each_implementation_for_trait<F>(cdata: Cmd,
     F: FnMut(DefId),
 {
     if cdata.cnum == def_id.krate {
-        let item_doc = cdata.lookup_item(def_id.node);
+        let item_doc = cdata.lookup_item(def_id.index);
         for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) {
             callback(item_def_id(impl_doc, cdata));
         }
@@ -1289,14 +1307,14 @@ pub fn each_implementation_for_trait<F>(cdata: Cmd,
     }
 }
 
-pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
+pub fn get_trait_of_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt)
                          -> Option<DefId> {
     let item_doc = cdata.lookup_item(id);
     let parent_item_id = match item_parent_item(cdata, item_doc) {
         None => return None,
         Some(item_id) => item_id,
     };
-    let parent_item_doc = cdata.lookup_item(parent_item_id.node);
+    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
     match item_family(parent_item_doc) {
         Trait => Some(item_def_id(parent_item_doc, cdata)),
         Impl | DefaultImpl => {
@@ -1322,9 +1340,9 @@ pub fn get_native_libraries(cdata: Cmd)
     }).collect()
 }
 
-pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
+pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
     reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
-        .map(|doc| reader::doc_as_u32(doc))
+        .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
 }
 
 pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
@@ -1376,7 +1394,7 @@ pub fn get_missing_lang_items(cdata: Cmd)
     }).collect()
 }
 
-pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
+pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
     let method_doc = cdata.lookup_item(id);
     match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
         Some(args_doc) => {
@@ -1394,12 +1412,12 @@ pub fn get_reachable_ids(cdata: Cmd) -> Vec<DefId> {
     reader::tagged_docs(items, tag_reachable_id).map(|doc| {
         DefId {
             krate: cdata.cnum,
-            node: reader::doc_as_u32(doc),
+            index: DefIndex::from_u32(reader::doc_as_u32(doc)),
         }
     }).collect()
 }
 
-pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool {
     let item_doc = cdata.lookup_item(id);
     match item_family(item_doc) {
         Type => true,
@@ -1407,7 +1425,7 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
     }
 }
 
-pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool {
     let item_doc = cdata.lookup_item(id);
     match fn_constness(item_doc) {
         hir::Constness::Const => true,
@@ -1415,7 +1433,7 @@ pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
     }
 }
 
-pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
     let item_doc = cdata.lookup_item(id);
     match item_family(item_doc) {
         Impl => true,
@@ -1435,7 +1453,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
     for p in reader::tagged_docs(doc, tag_type_param_def) {
         let bd =
             TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |_, did| translate_def_id(cdata, did))
+                                &mut |did| translate_def_id(cdata, did))
             .parse_type_param_def();
         types.push(bd.space, bd);
     }
@@ -1457,7 +1475,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
 
         let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| {
             TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |_, did| translate_def_id(cdata, did))
+                                &mut |did| translate_def_id(cdata, did))
             .parse_region()
         }).collect();
 
@@ -1480,7 +1498,7 @@ fn doc_predicate<'tcx>(cdata: Cmd,
         cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize;
     TyDecoder::new(
         cdata.data(), cdata.cnum, predicate_pos, tcx,
-        &mut |_, did| translate_def_id(cdata, did)
+        &mut |did| translate_def_id(cdata, did)
     ).parse_predicate()
 }
 
@@ -1509,14 +1527,14 @@ fn doc_predicates<'tcx>(base_doc: rbml::Doc,
     ty::GenericPredicates { predicates: predicates }
 }
 
-pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
+pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool {
     let trait_doc = cdata.lookup_item(trait_id);
     assert!(item_family(trait_doc) == Family::Trait);
     let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
     reader::doc_as_u8(defaulted_doc) != 0
 }
 
-pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool {
+pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool {
     let impl_doc = cdata.lookup_item(impl_id);
     item_family(impl_doc) == Family::DefaultImpl
 }
@@ -1531,7 +1549,7 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<codemap::FileMap> {
     }).collect()
 }
 
-pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool {
+pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool {
     let item_doc = match cdata.get_item(id) {
         Some(doc) => doc,
         None => return false,
@@ -1546,3 +1564,41 @@ pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool {
         false
     }
 }
+
+pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind {
+    let closure_doc = cdata.lookup_item(closure_id);
+    let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind);
+    let mut decoder = reader::Decoder::new(closure_kind_doc);
+    ty::ClosureKind::decode(&mut decoder).unwrap()
+}
+
+pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &ty::ctxt<'tcx>)
+                        -> ty::ClosureTy<'tcx> {
+    let closure_doc = cdata.lookup_item(closure_id);
+    let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty);
+    TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did))
+        .parse_closure_ty()
+}
+
+fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
+    match reader::maybe_get_doc(item_doc, tag_def_key) {
+        Some(def_key_doc) => {
+            let mut decoder = reader::Decoder::new(def_key_doc);
+            hir_map::DefKey::decode(&mut decoder).unwrap()
+        }
+        None => {
+            panic!("failed to find block with tag {:?} for item with family {:?}",
+                   tag_def_key,
+                   item_family(item_doc))
+        }
+    }
+}
+
+pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
+    debug!("def_path(id={:?})", id);
+    hir_map::definitions::make_def_path(id, |parent| {
+        debug!("def_path: parent={:?}", parent);
+        let parent_doc = cdata.lookup_item(parent);
+        def_key(parent_doc)
+    })
+}
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index dd23584994b..caccdbd3382 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -17,12 +17,13 @@ use back::svh::Svh;
 use session::config;
 use metadata::common::*;
 use metadata::cstore;
+use metadata::cstore::LOCAL_CRATE;
 use metadata::decoder;
 use metadata::tyencode;
-use metadata::index::{self, IndexEntry};
+use metadata::index::{self, IndexData};
 use metadata::inline::InlinedItemRef;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::dependency_format::Linkage;
 use middle::stability;
 use middle::subst;
@@ -34,6 +35,7 @@ use std::cell::RefCell;
 use std::io::prelude::*;
 use std::io::{Cursor, SeekFrom};
 use std::rc::Rc;
+use std::u32;
 use syntax::abi;
 use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
 use syntax::attr;
@@ -75,21 +77,25 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     pub reachable: &'a NodeSet,
 }
 
+impl<'a, 'tcx> EncodeContext<'a,'tcx> {
+    fn local_id(&self, def_id: DefId) -> NodeId {
+        self.tcx.map.as_local_node_id(def_id).unwrap()
+    }
+}
+
 /// "interned" entries referenced by id
 #[derive(PartialEq, Eq, Hash)]
 pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
 
 struct CrateIndex<'tcx> {
-    items: Vec<IndexEntry>,
+    items: IndexData,
     xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
 }
 
 impl<'tcx> CrateIndex<'tcx> {
-    fn index_item(&mut self, rbml_w: &mut Encoder, id: NodeId) {
-        self.items.push(IndexEntry {
-            node: id,
-            pos: rbml_w.mark_stable_position(),
-        });
+    fn record(&mut self, id: DefId, rbml_w: &mut Encoder) {
+        let position = rbml_w.mark_stable_position();
+        self.items.record(id, position);
     }
 
     fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
@@ -106,6 +112,26 @@ fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
     rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
 }
 
+/// For every DefId that we create a metadata item for, we include a
+/// serialized copy of its DefKey, which allows us to recreate a path.
+fn encode_def_id_and_key(ecx: &EncodeContext,
+                         rbml_w: &mut Encoder,
+                         def_id: DefId)
+{
+    encode_def_id(rbml_w, def_id);
+    encode_def_key(ecx, rbml_w, def_id);
+}
+
+fn encode_def_key(ecx: &EncodeContext,
+                  rbml_w: &mut Encoder,
+                  def_id: DefId)
+{
+    rbml_w.start_tag(tag_def_key);
+    let def_key = ecx.tcx.map.def_key(def_id);
+    def_key.encode(rbml_w);
+    rbml_w.end_tag();
+}
+
 fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
                               ecx: &EncodeContext<'a, 'tcx>,
                               trait_ref: ty::TraitRef<'tcx>,
@@ -128,17 +154,18 @@ fn encode_family(rbml_w: &mut Encoder, c: char) {
 }
 
 pub fn def_to_u64(did: DefId) -> u64 {
-    (did.krate as u64) << 32 | (did.node as u64)
+    assert!(did.index.as_u32() < u32::MAX);
+    (did.krate as u64) << 32 | (did.index.as_usize() as u64)
 }
 
 pub fn def_to_string(did: DefId) -> String {
-    format!("{}:{}", did.krate, did.node)
+    format!("{}:{}", did.krate, did.index.as_usize())
 }
 
 fn encode_item_variances(rbml_w: &mut Encoder,
                          ecx: &EncodeContext,
                          id: NodeId) {
-    let v = ecx.tcx.item_variances(DefId::local(id));
+    let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
     rbml_w.start_tag(tag_item_variances);
     v.encode(rbml_w);
     rbml_w.end_tag();
@@ -151,8 +178,8 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
     encode_bounds_and_type(rbml_w,
                            ecx,
                            index,
-                           &ecx.tcx.lookup_item_type(DefId::local(id)),
-                           &ecx.tcx.lookup_predicates(DefId::local(id)));
+                           &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
+                           &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
 }
 
 fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
@@ -283,10 +310,10 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     debug!("encode_enum_variant_info(id={})", id);
 
     let mut disr_val = 0;
-    let def = ecx.tcx.lookup_adt_def(DefId::local(id));
+    let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
     for variant in &def.variants {
         let vid = variant.did;
-        assert!(vid.is_local());
+        let variant_node_id = ecx.local_id(vid);
 
         if let ty::VariantKind::Dict = variant.kind() {
             // tuple-like enum variant fields aren't really items so
@@ -296,15 +323,15 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             }
         }
 
-        index.index_item(rbml_w, vid.node);
+        index.record(vid, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, vid);
+        encode_def_id_and_key(ecx, rbml_w, vid);
         encode_family(rbml_w, match variant.kind() {
             ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v',
             ty::VariantKind::Dict => 'V'
         });
         encode_name(rbml_w, variant.name);
-        encode_parent_item(rbml_w, DefId::local(id));
+        encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
         encode_visibility(rbml_w, vis);
 
         let attrs = ecx.tcx.get_attrs(vid);
@@ -321,9 +348,9 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             encode_disr_val(ecx, rbml_w, specified_disr_val);
             disr_val = specified_disr_val;
         }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, vid.node);
+        encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
 
-        ecx.tcx.map.with_path(vid.node, |path| encode_path(rbml_w, path));
+        ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
         rbml_w.end_tag();
         disr_val = disr_val.wrapping_add(1);
     }
@@ -343,107 +370,6 @@ fn encode_path<PI: Iterator<Item=PathElem>>(rbml_w: &mut Encoder, path: PI) {
     rbml_w.end_tag();
 }
 
-fn encode_reexported_static_method(rbml_w: &mut Encoder,
-                                   exp: &def::Export,
-                                   method_def_id: DefId,
-                                   method_name: Name) {
-    debug!("(encode reexported static method) {}::{}",
-            exp.name, method_name);
-    rbml_w.start_tag(tag_items_data_item_reexport);
-    rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
-                         def_to_u64(method_def_id));
-    rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
-                         &format!("{}::{}", exp.name,
-                                            method_name));
-    rbml_w.end_tag();
-}
-
-fn encode_reexported_static_base_methods(ecx: &EncodeContext,
-                                         rbml_w: &mut Encoder,
-                                         exp: &def::Export)
-                                         -> bool {
-    let impl_items = ecx.tcx.impl_items.borrow();
-    match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
-        Some(implementations) => {
-            for base_impl_did in implementations.iter() {
-                for &method_did in impl_items.get(base_impl_did).unwrap() {
-                    let impl_item = ecx.tcx.impl_or_trait_item(method_did.def_id());
-                    if let ty::MethodTraitItem(ref m) = impl_item {
-                        encode_reexported_static_method(rbml_w,
-                                                        exp,
-                                                        m.def_id,
-                                                        m.name);
-                    }
-                }
-            }
-
-            true
-        }
-        None => { false }
-    }
-}
-
-fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
-                                          rbml_w: &mut Encoder,
-                                          exp: &def::Export)
-                                          -> bool {
-    match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) {
-        Some(trait_items) => {
-            for trait_item in trait_items.iter() {
-                if let ty::MethodTraitItem(ref m) = *trait_item {
-                    encode_reexported_static_method(rbml_w,
-                                                    exp,
-                                                    m.def_id,
-                                                    m.name);
-                }
-            }
-            true
-        }
-        None => { false }
-    }
-}
-
-fn encode_reexported_static_methods(ecx: &EncodeContext,
-                                    rbml_w: &mut Encoder,
-                                    mod_path: PathElems,
-                                    exp: &def::Export) {
-    if let Some(ast_map::NodeItem(item)) = ecx.tcx.map.find(exp.def_id.node) {
-        let path_differs = ecx.tcx.map.with_path(exp.def_id.node, |path| {
-            let (mut a, mut b) = (path, mod_path.clone());
-            loop {
-                match (a.next(), b.next()) {
-                    (None, None) => return true,
-                    (None, _) | (_, None) => return false,
-                    (Some(x), Some(y)) => if x != y { return false },
-                }
-            }
-        });
-
-        //
-        // We don't need to reexport static methods on items
-        // declared in the same module as our `pub use ...` since
-        // that's done when we encode the item itself.
-        //
-        // The only exception is when the reexport *changes* the
-        // name e.g. `pub use Foo = self::Bar` -- we have
-        // encoded metadata for static methods relative to Bar,
-        // but not yet for Foo.
-        //
-        if path_differs || item.name != exp.name {
-            if !encode_reexported_static_base_methods(ecx, rbml_w, exp) {
-                if encode_reexported_static_trait_methods(ecx, rbml_w, exp) {
-                    debug!("(encode reexported static methods) {} [trait]",
-                           item.name);
-                }
-            }
-            else {
-                debug!("(encode reexported static methods) {} [base]",
-                       item.name);
-            }
-        }
-    }
-}
-
 /// Iterates through "auxiliary node IDs", which are node IDs that describe
 /// top-level items that are sub-items of the given item. Specifically:
 ///
@@ -471,18 +397,16 @@ fn each_auxiliary_node_id<F>(item: &hir::Item, callback: F) -> bool where
 
 fn encode_reexports(ecx: &EncodeContext,
                     rbml_w: &mut Encoder,
-                    id: NodeId,
-                    path: PathElems) {
+                    id: NodeId) {
     debug!("(encoding info for module) encoding reexports for {}", id);
     match ecx.reexports.get(&id) {
         Some(exports) => {
             debug!("(encoding info for module) found reexports for {}", id);
             for exp in exports {
-                debug!("(encoding info for module) reexport '{}' ({}/{}) for \
+                debug!("(encoding info for module) reexport '{}' ({:?}) for \
                         {}",
                        exp.name,
-                       exp.def_id.krate,
-                       exp.def_id.node,
+                       exp.def_id,
                        id);
                 rbml_w.start_tag(tag_items_data_item_reexport);
                 rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
@@ -490,7 +414,6 @@ fn encode_reexports(ecx: &EncodeContext,
                 rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
                                      &exp.name.as_str());
                 rbml_w.end_tag();
-                encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp);
             }
         },
         None => debug!("(encoding info for module) found no reexports for {}", id),
@@ -506,7 +429,7 @@ fn encode_info_for_mod(ecx: &EncodeContext,
                        name: Name,
                        vis: hir::Visibility) {
     rbml_w.start_tag(tag_items_data_item);
-    encode_def_id(rbml_w, DefId::local(id));
+    encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id));
     encode_family(rbml_w, 'm');
     encode_name(rbml_w, name);
     debug!("(encoding info for module) encoding info for module ID {}", id);
@@ -514,11 +437,11 @@ fn encode_info_for_mod(ecx: &EncodeContext,
     // Encode info about all the module children.
     for item in &md.items {
         rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(DefId::local(item.id)));
+                             def_to_u64(ecx.tcx.map.local_def_id(item.id)));
 
         each_auxiliary_node_id(&**item, |auxiliary_node_id| {
             rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(DefId::local(auxiliary_node_id)));
+                                 def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
             true
         });
     }
@@ -526,13 +449,13 @@ fn encode_info_for_mod(ecx: &EncodeContext,
     encode_path(rbml_w, path.clone());
     encode_visibility(rbml_w, vis);
 
-    let stab = stability::lookup(ecx.tcx, DefId::local(id));
+    let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id));
     encode_stability(rbml_w, stab);
 
     // Encode the reexports of this module, if this module is public.
     if vis == hir::Public {
         debug!("(encoding info for module) encoding reexports for {}", id);
-        encode_reexports(ecx, rbml_w, id, path);
+        encode_reexports(ecx, rbml_w, id);
     }
     encode_attributes(rbml_w, attrs);
 
@@ -604,15 +527,15 @@ fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                           field: ty::FieldDef<'tcx>,
                           index: &mut CrateIndex<'tcx>) {
     let nm = field.name;
-    let id = field.did.node;
+    let id = ecx.local_id(field.did);
 
-    index.index_item(rbml_w, id);
+    index.record(field.did, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
     debug!("encode_field: encoding {} {}", nm, id);
     encode_struct_field_family(rbml_w, field.vis);
     encode_name(rbml_w, nm);
     encode_bounds_and_type_for_item(rbml_w, ecx, index, id);
-    encode_def_id(rbml_w, DefId::local(id));
+    encode_def_id_and_key(ecx, rbml_w, field.did);
 
     let stab = stability::lookup(ecx.tcx, field.did);
     encode_stability(rbml_w, stab);
@@ -626,20 +549,22 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                          ctor_id: NodeId,
                                          index: &mut CrateIndex<'tcx>,
                                          struct_id: NodeId) {
-    index.index_item(rbml_w, ctor_id);
+    let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
+
+    index.record(ctor_def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
-    encode_def_id(rbml_w, DefId::local(ctor_id));
+    encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
     encode_family(rbml_w, 'o');
     encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
     encode_name(rbml_w, name);
     ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
-    encode_parent_item(rbml_w, DefId::local(struct_id));
+    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
 
     if ecx.item_symbols.borrow().contains_key(&ctor_id) {
         encode_symbol(ecx, rbml_w, ctor_id);
     }
 
-    let stab = stability::lookup(ecx.tcx, DefId::local(ctor_id));
+    let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id));
     encode_stability(rbml_w, stab);
 
     // indicate that this is a tuple struct ctor, because downstream users will normally want
@@ -734,7 +659,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                      rbml_w: &mut Encoder,
                                      index: &mut CrateIndex<'tcx>,
                                      method_ty: &ty::Method<'tcx>) {
-    encode_def_id(rbml_w, method_ty.def_id);
+    encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
     encode_name(rbml_w, method_ty.name);
     encode_generics(rbml_w, ecx, index,
                     &method_ty.generics, &method_ty.predicates,
@@ -760,19 +685,19 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
            associated_const.def_id,
            associated_const.name);
 
-    index.index_item(rbml_w, associated_const.def_id.node);
+    index.record(associated_const.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
-    encode_def_id(rbml_w, associated_const.def_id);
+    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
     encode_name(rbml_w, associated_const.name);
     encode_visibility(rbml_w, associated_const.vis);
     encode_family(rbml_w, 'C');
 
-    encode_parent_item(rbml_w, DefId::local(parent_id));
+    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
     encode_item_sort(rbml_w, 'C');
 
     encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                    associated_const.def_id.local_id());
+                                    ecx.local_id(associated_const.def_id));
 
     let stab = stability::lookup(ecx.tcx, associated_const.def_id);
     encode_stability(rbml_w, stab);
@@ -782,7 +707,10 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     if let Some(ii) = impl_item_opt {
         encode_attributes(rbml_w, &ii.attrs);
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id), ii));
+        encode_inlined_item(ecx,
+                            rbml_w,
+                            InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+                                                     ii));
     }
 
     rbml_w.end_tag();
@@ -799,17 +727,18 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     debug!("encode_info_for_method: {:?} {:?}", m.def_id,
            m.name);
-    index.index_item(rbml_w, m.def_id.node);
+    index.record(m.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
     encode_method_ty_fields(ecx, rbml_w, index, m);
-    encode_parent_item(rbml_w, DefId::local(parent_id));
+    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
     encode_item_sort(rbml_w, 'r');
 
     let stab = stability::lookup(ecx.tcx, m.def_id);
     encode_stability(rbml_w, stab);
 
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, m.def_id.local_id());
+    let m_node_id = ecx.local_id(m.def_id);
+    encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id);
 
     let elem = ast_map::PathName(m.name);
     encode_path(rbml_w, impl_path.chain(Some(elem)));
@@ -821,12 +750,15 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             let needs_inline = any_types || is_default_impl ||
                                attr::requests_inline(&impl_item.attrs);
             if needs_inline || sig.constness == hir::Constness::Const {
-                encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id),
-                                                               impl_item));
+                encode_inlined_item(ecx,
+                                    rbml_w,
+                                    InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+                                                             impl_item));
             }
             encode_constness(rbml_w, sig.constness);
             if !any_types {
-                encode_symbol(ecx, rbml_w, m.def_id.node);
+                let m_id = ecx.local_id(m.def_id);
+                encode_symbol(ecx, rbml_w, m_id);
             }
             encode_method_argument_names(rbml_w, &sig.decl);
         }
@@ -846,14 +778,14 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
            associated_type.def_id,
            associated_type.name);
 
-    index.index_item(rbml_w, associated_type.def_id.node);
+    index.record(associated_type.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
-    encode_def_id(rbml_w, associated_type.def_id);
+    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
     encode_name(rbml_w, associated_type.name);
     encode_visibility(rbml_w, associated_type.vis);
     encode_family(rbml_w, 'y');
-    encode_parent_item(rbml_w, DefId::local(parent_id));
+    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
     encode_item_sort(rbml_w, 't');
 
     let stab = stability::lookup(ecx.tcx, associated_type.def_id);
@@ -994,14 +926,14 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     debug!("encoding info for item at {}",
            tcx.sess.codemap().span_to_string(item.span));
 
-    let def_id = DefId::local(item.id);
-    let stab = stability::lookup(tcx, DefId::local(item.id));
+    let def_id = ecx.tcx.map.local_def_id(item.id);
+    let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id));
 
     match item.node {
       hir::ItemStatic(_, m, _) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         if m == hir::MutMutable {
             encode_family(rbml_w, 'b');
         } else {
@@ -1017,9 +949,9 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemConst(_, _) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'C');
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
         encode_name(rbml_w, item.name);
@@ -1031,9 +963,9 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, FN_FAMILY);
         let tps_len = generics.ty_params.len();
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
@@ -1054,7 +986,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemMod(ref m) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         encode_info_for_mod(ecx,
                             rbml_w,
                             m,
@@ -1065,9 +997,9 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                             item.vis);
       }
       hir::ItemForeignMod(ref fm) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'n');
         encode_name(rbml_w, item.name);
         encode_path(rbml_w, path);
@@ -1075,16 +1007,16 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         // Encode all the items in this module.
         for foreign_item in &fm.items {
             rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(DefId::local(foreign_item.id)));
+                                 def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
         }
         encode_visibility(rbml_w, vis);
         encode_stability(rbml_w, stab);
         rbml_w.end_tag();
       }
       hir::ItemTy(..) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'y');
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
         encode_name(rbml_w, item.name);
@@ -1094,10 +1026,10 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemEnum(ref enum_definition, _) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
 
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 't');
         encode_item_variances(rbml_w, ecx, item.id);
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
@@ -1105,7 +1037,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_attributes(rbml_w, &item.attrs);
         encode_repr_attrs(rbml_w, ecx, &item.attrs);
         for v in &enum_definition.variants {
-            encode_variant_id(rbml_w, DefId::local(v.node.id));
+            encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.id));
         }
         encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
         encode_path(rbml_w, path);
@@ -1128,11 +1060,11 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         let variant = def.struct_variant();
 
         /* Index the class*/
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
 
         /* Now, make an item for the class itself */
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'S');
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
 
@@ -1154,6 +1086,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         // Encode inherent implementations for this structure.
         encode_inherent_implementations(ecx, rbml_w, def_id);
 
+        if let Some(ctor_id) = struct_def.ctor_id {
+            let ctor_did = ecx.tcx.map.local_def_id(ctor_id);
+            rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
+                                 def_to_u64(ctor_did));
+        }
+
         rbml_w.end_tag();
 
         for field in &variant.fields {
@@ -1161,23 +1099,20 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         }
 
         // If this is a tuple-like struct, encode the type of the constructor.
-        match struct_def.ctor_id {
-            Some(ctor_id) => {
-                encode_info_for_struct_ctor(ecx, rbml_w, item.name,
-                                            ctor_id, index, def_id.node);
-            }
-            None => {}
+        if let Some(ctor_id) = struct_def.ctor_id {
+            encode_info_for_struct_ctor(ecx, rbml_w, item.name,
+                                        ctor_id, index, item.id);
         }
       }
       hir::ItemDefaultImpl(unsafety, _) => {
-          index.index_item(rbml_w, item.id);
+          index.record(def_id, rbml_w);
           rbml_w.start_tag(tag_items_data_item);
-          encode_def_id(rbml_w, def_id);
+          encode_def_id_and_key(ecx, rbml_w, def_id);
           encode_family(rbml_w, 'd');
           encode_name(rbml_w, item.name);
           encode_unsafety(rbml_w, unsafety);
 
-          let trait_ref = tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+          let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
           encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
           rbml_w.end_tag();
       }
@@ -1187,9 +1122,9 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         let impl_items = tcx.impl_items.borrow();
         let items = impl_items.get(&def_id).unwrap();
 
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'i');
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
         encode_name(rbml_w, item.name);
@@ -1197,7 +1132,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_unsafety(rbml_w, unsafety);
         encode_polarity(rbml_w, polarity);
 
-        match tcx.custom_coerce_unsized_kinds.borrow().get(&DefId::local(item.id)) {
+        match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) {
             Some(&kind) => {
                 rbml_w.start_tag(tag_impl_coerce_unsized_kind);
                 kind.encode(rbml_w);
@@ -1224,7 +1159,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             }
             rbml_w.end_tag();
         }
-        if let Some(trait_ref) = tcx.impl_trait_ref(DefId::local(item.id)) {
+        if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) {
             encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
         }
         encode_path(rbml_w, path.clone());
@@ -1276,9 +1211,9 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         }
       }
       hir::ItemTrait(_, _, _, ref ms) => {
-        index.index_item(rbml_w, item.id);
+        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
-        encode_def_id(rbml_w, def_id);
+        encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'I');
         encode_item_variances(rbml_w, ecx, item.id);
         let trait_def = tcx.lookup_trait_def(def_id);
@@ -1334,7 +1269,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         for (i, &item_def_id) in r.iter().enumerate() {
             assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
 
-            index.index_item(rbml_w, item_def_id.def_id().node);
+            index.record(item_def_id.def_id(), rbml_w);
             rbml_w.start_tag(tag_items_data_item);
 
             encode_parent_item(rbml_w, def_id);
@@ -1348,7 +1283,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             match trait_item_type {
                 ty::ConstTraitItem(associated_const) => {
                     encode_name(rbml_w, associated_const.name);
-                    encode_def_id(rbml_w, associated_const.def_id);
+                    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
                     encode_visibility(rbml_w, associated_const.vis);
 
                     let elem = ast_map::PathName(associated_const.name);
@@ -1358,7 +1293,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                     encode_family(rbml_w, 'C');
 
                     encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    associated_const.def_id.local_id());
+                                                    ecx.local_id(associated_const.def_id));
 
                     is_nonstatic_method = false;
                 }
@@ -1382,14 +1317,14 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                         }
                     }
                     encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    method_def_id.local_id());
+                                                    ecx.local_id(method_def_id));
 
                     is_nonstatic_method = method_ty.explicit_self !=
                         ty::StaticExplicitSelfCategory;
                 }
                 ty::TypeTraitItem(associated_type) => {
                     encode_name(rbml_w, associated_type.name);
-                    encode_def_id(rbml_w, associated_type.def_id);
+                    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
 
                     let elem = ast_map::PathName(associated_type.name);
                     encode_path(rbml_w,
@@ -1426,7 +1361,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                         // FIXME: I feel like there is something funny
                         // going on.
                         encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                            item_def_id.def_id().local_id());
+                                                        ecx.local_id(item_def_id.def_id()));
                     }
 
                     if body.is_some() {
@@ -1457,9 +1392,11 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                           index: &mut CrateIndex<'tcx>,
                                           path: PathElems,
                                           abi: abi::Abi) {
-    index.index_item(rbml_w, nitem.id);
+    let def_id = ecx.tcx.map.local_def_id(nitem.id);
+
+    index.record(def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
-    encode_def_id(rbml_w, DefId::local(nitem.id));
+    encode_def_id_and_key(ecx, rbml_w, def_id);
     encode_visibility(rbml_w, nitem.vis);
     match nitem.node {
       hir::ForeignItemFn(ref fndecl, _) => {
@@ -1470,7 +1407,7 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem));
         }
         encode_attributes(rbml_w, &*nitem.attrs);
-        let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id));
+        let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id));
         encode_stability(rbml_w, stab);
         encode_symbol(ecx, rbml_w, nitem.id);
         encode_method_argument_names(rbml_w, &*fndecl);
@@ -1483,7 +1420,7 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         }
         encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
         encode_attributes(rbml_w, &*nitem.attrs);
-        let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id));
+        let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id));
         encode_stability(rbml_w, stab);
         encode_symbol(ecx, rbml_w, nitem.id);
         encode_name(rbml_w, nitem.name);
@@ -1493,7 +1430,34 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     rbml_w.end_tag();
 }
 
-fn my_visit_expr(_e: &hir::Expr) { }
+fn my_visit_expr(expr: &hir::Expr,
+                 rbml_w: &mut Encoder,
+                 ecx: &EncodeContext,
+                 index: &mut CrateIndex) {
+    match expr.node {
+        hir::ExprClosure(..) => {
+            let def_id = ecx.tcx.map.local_def_id(expr.id);
+
+            index.record(def_id, rbml_w);
+
+            rbml_w.start_tag(tag_items_data_item);
+            encode_def_id_and_key(ecx, rbml_w, def_id);
+
+            rbml_w.start_tag(tag_items_closure_ty);
+            write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]);
+            rbml_w.end_tag();
+
+            rbml_w.start_tag(tag_items_closure_kind);
+            ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
+            rbml_w.end_tag();
+
+            ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path));
+
+            rbml_w.end_tag();
+        }
+        _ => { }
+    }
+}
 
 fn my_visit_item<'a, 'tcx>(i: &hir::Item,
                            rbml_w: &mut Encoder,
@@ -1529,21 +1493,15 @@ struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
 impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
     fn visit_expr(&mut self, ex: &hir::Expr) {
         visit::walk_expr(self, ex);
-        my_visit_expr(ex);
+        my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
     fn visit_item(&mut self, i: &hir::Item) {
         visit::walk_item(self, i);
-        my_visit_item(i,
-                      self.rbml_w_for_visit_item,
-                      self.ecx,
-                      self.index);
+        my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
     fn visit_foreign_item(&mut self, ni: &hir::ForeignItem) {
         visit::walk_foreign_item(self, ni);
-        my_visit_foreign_item(ni,
-                              self.rbml_w_for_visit_item,
-                              self.ecx,
-                              self.index);
+        my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
 }
 
@@ -1552,12 +1510,12 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                    krate: &hir::Crate)
                                    -> CrateIndex<'tcx> {
     let mut index = CrateIndex {
-        items: Vec::new(),
+        items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
         xrefs: FnvHashMap()
     };
     rbml_w.start_tag(tag_items_data);
 
-    index.index_item(rbml_w, CRATE_NODE_ID);
+    index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
     encode_info_for_mod(ecx,
                         rbml_w,
                         &krate.module,
@@ -1577,10 +1535,9 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     index
 }
 
-fn encode_item_index(rbml_w: &mut Encoder, index: Vec<IndexEntry>)
-{
+fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
     rbml_w.start_tag(tag_index);
-    index::write_index(index, rbml_w.writer);
+    index.write_index(rbml_w.writer);
     rbml_w.end_tag();
 }
 
@@ -1694,12 +1651,12 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
 fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
     rbml_w.start_tag(tag_lang_items);
 
-    for (i, &def_id) in ecx.tcx.lang_items.items() {
-        if let Some(id) = def_id {
-            if id.is_local() {
+    for (i, &opt_def_id) in ecx.tcx.lang_items.items() {
+        if let Some(def_id) = opt_def_id {
+            if def_id.is_local() {
                 rbml_w.start_tag(tag_lang_items_item);
                 rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
-                rbml_w.wr_tagged_u32(tag_lang_items_item_node_id, id.node as u32);
+                rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
                 rbml_w.end_tag();
             }
         }
@@ -1733,7 +1690,10 @@ fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
 
 fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
     match ecx.tcx.sess.plugin_registrar_fn.get() {
-        Some(id) => { rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, id); }
+        Some(id) => {
+            let def_id = ecx.tcx.map.local_def_id(id);
+            rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
+        }
         None => {}
     }
 }
@@ -1778,24 +1738,26 @@ fn encode_macro_defs(rbml_w: &mut Encoder,
     rbml_w.end_tag();
 }
 
-fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &hir::Crate) {
-    struct StructFieldVisitor<'a, 'b:'a> {
-        rbml_w: &'a mut Encoder<'b>,
+fn encode_struct_field_attrs(ecx: &EncodeContext,
+                             rbml_w: &mut Encoder,
+                             krate: &hir::Crate) {
+    struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
+        ecx: &'a EncodeContext<'b, 'tcx>,
+        rbml_w: &'a mut Encoder<'c>,
     }
 
-    impl<'a, 'b, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b> {
+    impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> {
         fn visit_struct_field(&mut self, field: &hir::StructField) {
             self.rbml_w.start_tag(tag_struct_field);
-            self.rbml_w.wr_tagged_u32(tag_struct_field_id, field.node.id);
+            let def_id = self.ecx.tcx.map.local_def_id(field.node.id);
+            encode_def_id(self.rbml_w, def_id);
             encode_attributes(self.rbml_w, &field.node.attrs);
             self.rbml_w.end_tag();
         }
     }
 
     rbml_w.start_tag(tag_struct_fields);
-    visit::walk_crate(&mut StructFieldVisitor {
-        rbml_w: rbml_w
-    }, krate);
+    visit::walk_crate(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }, krate);
     rbml_w.end_tag();
 }
 
@@ -1816,7 +1778,7 @@ impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
             if Some(def_id) == self.ecx.tcx.lang_items.drop_trait() ||
                     def_id.krate != LOCAL_CRATE {
                 self.rbml_w.start_tag(tag_impls_impl);
-                encode_def_id(self.rbml_w, DefId::local(item.id));
+                encode_def_id(self.rbml_w, self.ecx.tcx.map.local_def_id(item.id));
                 self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id));
                 self.rbml_w.end_tag();
             }
@@ -1858,17 +1820,17 @@ fn encode_misc_info(ecx: &EncodeContext,
     rbml_w.start_tag(tag_misc_info_crate_items);
     for item in &krate.module.items {
         rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(DefId::local(item.id)));
+                             def_to_u64(ecx.tcx.map.local_def_id(item.id)));
 
         each_auxiliary_node_id(&**item, |auxiliary_node_id| {
             rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(DefId::local(auxiliary_node_id)));
+                                 def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
             true
         });
     }
 
     // Encode reexports for the root module.
-    encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty()));
+    encode_reexports(ecx, rbml_w, 0);
 
     rbml_w.end_tag();
     rbml_w.end_tag();
@@ -1882,8 +1844,9 @@ fn encode_misc_info(ecx: &EncodeContext,
 // definition (as that's not defined in this crate).
 fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
     rbml_w.start_tag(tag_reachable_ids);
-    for id in ecx.reachable {
-        rbml_w.wr_tagged_u32(tag_reachable_id, *id);
+    for &id in ecx.reachable {
+        let def_id = ecx.tcx.map.local_def_id(id);
+        rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
     }
     rbml_w.end_tag();
 }
@@ -2102,7 +2065,7 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
     encode_xrefs(&ecx, &mut rbml_w, index.xrefs);
     stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
 
-    encode_struct_field_attrs(&mut rbml_w, krate);
+    encode_struct_field_attrs(&ecx, &mut rbml_w, krate);
 
     stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
 
diff --git a/src/librustc/metadata/index.rs b/src/librustc/metadata/index.rs
index 1cfb201023b..60bbdaddd75 100644
--- a/src/librustc/metadata/index.rs
+++ b/src/librustc/metadata/index.rs
@@ -8,148 +8,98 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::def_id::{DefId, DefIndex};
+use rbml;
 use std::io::{Cursor, Write};
 use std::slice;
 use std::u32;
-use syntax::ast::NodeId;
 
-#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
-pub struct IndexEntry {
-    pub node: NodeId,
-    pub pos: u64
-}
-
-#[derive(Debug)]
-pub struct IndexArrayEntry {
-    bits: u32,
-    first_pos: u32
+/// As part of the metadata, we generate an index that stores, for
+/// each DefIndex, the position of the corresponding RBML document (if
+/// any).  This is just a big `[u32]` slice, where an entry of
+/// `u32::MAX` indicates that there is no RBML document. This little
+/// struct just stores the offsets within the metadata of the start
+/// and end of this slice. These are actually part of an RBML
+/// document, but for looking things up in the metadata, we just
+/// discard the RBML positioning and jump directly to the data.
+pub struct Index {
+    data_start: usize,
+    data_end: usize,
 }
 
-impl IndexArrayEntry {
-    fn encode_to<W: Write>(&self, b: &mut W) {
-        write_be_u32(b, self.bits);
-        write_be_u32(b, self.first_pos);
+impl Index {
+    /// Given the RBML doc representing the index, save the offests
+    /// for later.
+    pub fn from_rbml(index: rbml::Doc) -> Index {
+        Index { data_start: index.start, data_end: index.end }
     }
 
-    fn decode_from(b: &[u32]) -> Self {
-        IndexArrayEntry {
-            bits: u32::from_be(b[0]),
-            first_pos: u32::from_be(b[1])
+    /// Given the metadata, extract out the offset of a particular
+    /// DefIndex (if any).
+    #[inline(never)]
+    pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
+        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
+        let index = def_index.as_usize();
+
+        debug!("lookup_item: index={:?} words.len={:?}",
+               index, words.len());
+
+        let position = u32::from_be(words[index]);
+        if position == u32::MAX {
+            debug!("lookup_item: position=u32::MAX");
+            None
+        } else {
+            debug!("lookup_item: position={:?}", position);
+            Some(position)
         }
     }
 }
 
-/// The Item Index
-///
-/// This index maps the NodeId of each item to its location in the
-/// metadata.
-///
-/// The index is a sparse bit-vector consisting of a index-array
-/// and a position-array. Each entry in the index-array handles 32 nodes.
-/// The first word is a bit-array consisting of the nodes that hold items,
-/// the second is the index of the first of the items in the position-array.
-/// If there is a large set of non-item trailing nodes, they can be omitted
-/// from the index-array.
-///
-/// The index is serialized as an array of big-endian 32-bit words.
-/// The first word is the number of items in the position-array.
-/// Then, for each item, its position in the metadata follows.
-/// After that the index-array is stored.
-///
-/// struct index {
-///     u32 item_count;
-///     u32 items[self.item_count];
-///     struct { u32 bits; u32 offset; } positions[..];
-/// }
-pub struct Index {
-    position_start: usize,
-    index_start: usize,
-    index_end: usize,
+/// While we are generating the metadata, we also track the position
+/// of each DefIndex. It is not required that all definitions appear
+/// in the metadata, nor that they are serialized in order, and
+/// therefore we first allocate the vector here and fill it with
+/// `u32::MAX`. Whenever an index is visited, we fill in the
+/// appropriate spot by calling `record_position`. We should never
+/// visit the same index twice.
+pub struct IndexData {
+    positions: Vec<u32>,
 }
 
-pub fn write_index(mut entries: Vec<IndexEntry>, buf: &mut Cursor<Vec<u8>>) {
-    assert!(entries.len() < u32::MAX as usize);
-    entries.sort();
-
-    let mut last_entry = IndexArrayEntry { bits: 0, first_pos: 0 };
-
-    write_be_u32(buf, entries.len() as u32);
-    for &IndexEntry { pos, .. } in &entries {
-        assert!(pos < u32::MAX as u64);
-        write_be_u32(buf, pos as u32);
+impl IndexData {
+    pub fn new(max_index: usize) -> IndexData {
+        IndexData {
+            positions: vec![u32::MAX; max_index]
+        }
     }
 
-    let mut pos_in_index_array = 0;
-    for (i, &IndexEntry { node, .. }) in entries.iter().enumerate() {
-        let (x, s) = (node / 32 as u32, node % 32 as u32);
-        while x > pos_in_index_array {
-            pos_in_index_array += 1;
-            last_entry.encode_to(buf);
-            last_entry = IndexArrayEntry { bits: 0, first_pos: i as u32 };
-        }
-        last_entry.bits |= 1<<s;
+    pub fn record(&mut self, def_id: DefId, position: u64) {
+        assert!(def_id.is_local());
+        self.record_index(def_id.index, position)
     }
-    last_entry.encode_to(buf);
 
-    info!("write_index: {} items, {} array entries",
-          entries.len(), pos_in_index_array);
-}
+    pub fn record_index(&mut self, item: DefIndex, position: u64) {
+        let item = item.as_usize();
 
-impl Index {
-    fn lookup_index(&self, index: &[u32], i: u32) -> Option<IndexArrayEntry> {
-        let ix = (i as usize)*2;
-        if ix >= index.len() {
-            None
-        } else {
-            Some(IndexArrayEntry::decode_from(&index[ix..ix+2]))
-        }
-    }
+        assert!(position < (u32::MAX as u64));
+        let position = position as u32;
 
-    fn item_from_pos(&self, positions: &[u32], pos: u32) -> u32 {
-        u32::from_be(positions[pos as usize])
-    }
+        assert!(self.positions[item] == u32::MAX,
+                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
+                item, self.positions[item], position);
 
-    #[inline(never)]
-    pub fn lookup_item(&self, buf: &[u8], node: NodeId) -> Option<u32> {
-        let index = bytes_to_words(&buf[self.index_start..self.index_end]);
-        let positions = bytes_to_words(&buf[self.position_start..self.index_start]);
-        let (x, s) = (node / 32 as u32, node % 32 as u32);
-        let result = match self.lookup_index(index, x) {
-            Some(IndexArrayEntry { bits, first_pos }) => {
-                let bit = 1<<s;
-                if bits & bit == 0 {
-                    None
-                } else {
-                    let prev_nodes_for_entry = (bits&(bit-1)).count_ones();
-                    Some(self.item_from_pos(
-                        positions,
-                        first_pos+prev_nodes_for_entry))
-                }
-            }
-            None => None // trailing zero
-        };
-        debug!("lookup_item({:?}) = {:?}", node, result);
-        result
+        self.positions[item] = position;
     }
 
-    pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
-        let buf = bytes_to_words(&buf[start..end]);
-        let position_count = buf[0].to_be() as usize;
-        let position_len = position_count*4;
-        info!("loaded index - position: {}-{}-{}", start, start+position_len, end);
-        debug!("index contents are {:?}",
-               buf.iter().map(|b| format!("{:08x}", b)).collect::<Vec<_>>().concat());
-        assert!(end-4-start >= position_len);
-        assert_eq!((end-4-start-position_len)%8, 0);
-        Index {
-            position_start: start+4,
-            index_start: start+position_len+4,
-            index_end: end
+    pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
+        for &position in &self.positions {
+            write_be_u32(buf, position);
         }
     }
 }
 
-/// A dense index with integer keys
+/// A dense index with integer keys. Different API from IndexData (should
+/// these be merged?)
 pub struct DenseIndex {
     start: usize,
     end: usize
@@ -193,47 +143,3 @@ fn bytes_to_words(b: &[u8]) -> &[u32] {
     assert!(b.len() % 4 == 0);
     unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
 }
-
-#[test]
-fn test_index() {
-    let entries = vec![
-        IndexEntry { node: 0, pos: 17 },
-        IndexEntry { node: 31, pos: 29 },
-        IndexEntry { node: 32, pos: 1175 },
-        IndexEntry { node: 191, pos: 21 },
-        IndexEntry { node: 128, pos: 34 },
-        IndexEntry { node: 145, pos: 70 },
-        IndexEntry { node: 305, pos: 93214 },
-        IndexEntry { node: 138, pos: 64 },
-        IndexEntry { node: 129, pos: 53 },
-        IndexEntry { node: 192, pos: 33334 },
-        IndexEntry { node: 200, pos: 80123 },
-    ];
-    let mut c = Cursor::new(vec![]);
-    write_index(entries.clone(), &mut c);
-    let mut buf = c.into_inner();
-    let expected: &[u8] = &[
-        0, 0, 0, 11, // # entries
-        // values:
-        0,0,0,17, 0,0,0,29, 0,0,4,151, 0,0,0,34,
-        0,0,0,53, 0,0,0,64, 0,0,0,70, 0,0,0,21,
-        0,0,130,54, 0,1,56,251, 0,1,108,30,
-        // index:
-        128,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,2,
-        0,0,0,0,0,0,0,3,   0,0,0,0,0,0,0,3,
-        0,2,4,3,0,0,0,3,   128,0,0,0,0,0,0,7,
-        0,0,1,1,0,0,0,8,   0,0,0,0,0,0,0,10,
-        0,0,0,0,0,0,0,10,  0,2,0,0,0,0,0,10
-    ];
-    assert_eq!(buf, expected);
-
-    // insert some junk padding
-    for i in 0..17 { buf.insert(0, i); buf.push(i) }
-    let index = Index::from_buf(&buf, 17, buf.len()-17);
-
-    // test round-trip
-    for i in 0..4096 {
-        assert_eq!(index.lookup_item(&buf, i),
-                   entries.iter().find(|e| e.node == i).map(|n| n.pos as u32));
-    }
-}
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 8e5b09b81c7..d03af6b6722 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -16,11 +16,9 @@
 
 #![allow(non_camel_case_types)]
 
-pub use self::DefIdSource::*;
-
 use rustc_front::hir;
 
-use middle::def_id::DefId;
+use middle::def_id::{DefId, DefIndex};
 use middle::region;
 use middle::subst;
 use middle::subst::VecPerParamSpace;
@@ -36,32 +34,7 @@ use syntax::parse::token;
 // parse_from_str. Extra parameters are for converting to/from def_ids in the
 // data buffer. Whatever format you choose should not contain pipe characters.
 
-// Def id conversion: when we encounter def-ids, they have to be translated.
-// For example, the crate number must be converted from the crate number used
-// in the library we are reading from into the local crate numbers in use
-// here.  To perform this translation, the type decoder is supplied with a
-// conversion function of type `conv_did`.
-//
-// Sometimes, particularly when inlining, the correct translation of the
-// def-id will depend on where it originated from.  Therefore, the conversion
-// function is given an indicator of the source of the def-id.  See
-// astencode.rs for more information.
-#[derive(Copy, Clone, Debug)]
-pub enum DefIdSource {
-    // Identifies a struct, trait, enum, etc.
-    NominalType,
-
-    // Identifies a type alias (`type X = ...`).
-    TypeWithId,
-
-    // Identifies a region parameter (`fn foo<'X>() { ... }`).
-    RegionParameter,
-
-    // Identifies a closure
-    ClosureSource
-}
-
-pub type DefIdConvert<'a> = &'a mut FnMut(DefIdSource, DefId) -> DefId;
+pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId;
 
 pub struct TyDecoder<'a, 'tcx: 'a> {
     data: &'a [u8],
@@ -189,7 +162,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 ty::BrAnon(id)
             }
             '[' => {
-                let def = self.parse_def(RegionParameter);
+                let def = self.parse_def();
                 let name = token::intern(&self.parse_str(']'));
                 ty::BrNamed(def, name)
             }
@@ -215,19 +188,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'B' => {
                 assert_eq!(self.next(), '[');
-                // this is the wrong NodeId, but `param_id` is only accessed
-                // by the receiver-matching code in collect, which won't
-                // be going down this code path, and anyway I will kill it
-                // the moment wfcheck becomes the standard.
-                let node_id = self.parse_uint() as ast::NodeId;
-                assert_eq!(self.next(), '|');
+                let def_id = self.parse_def();
                 let space = self.parse_param_space();
                 assert_eq!(self.next(), '|');
                 let index = self.parse_u32();
                 assert_eq!(self.next(), '|');
                 let name = token::intern(&self.parse_str(']'));
                 ty::ReEarlyBound(ty::EarlyBoundRegion {
-                    param_id: node_id,
+                    def_id: def_id,
                     space: space,
                     index: index,
                     name: name
@@ -320,7 +288,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
     }
 
     pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> {
-        let def = self.parse_def(NominalType);
+        let def = self.parse_def();
         let substs = self.tcx.mk_substs(self.parse_substs());
         ty::TraitRef {def_id: def, substs: substs}
     }
@@ -349,7 +317,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             'c' => return tcx.types.char,
             't' => {
                 assert_eq!(self.next(), '[');
-                let did = self.parse_def(NominalType);
+                let did = self.parse_def();
                 let substs = self.parse_substs();
                 assert_eq!(self.next(), ']');
                 let def = self.tcx.lookup_adt_def(did);
@@ -396,7 +364,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 return tcx.mk_tup(params);
             }
             'F' => {
-                let def_id = self.parse_def(NominalType);
+                let def_id = self.parse_def();
                 return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty()));
             }
             'G' => {
@@ -435,13 +403,13 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 return tt;
             }
             '\"' => {
-                let _ = self.parse_def(TypeWithId);
+                let _ = self.parse_def();
                 let inner = self.parse_ty();
                 inner
             }
             'a' => {
                 assert_eq!(self.next(), '[');
-                let did = self.parse_def(NominalType);
+                let did = self.parse_def();
                 let substs = self.parse_substs();
                 assert_eq!(self.next(), ']');
                 let def = self.tcx.lookup_adt_def(did);
@@ -449,7 +417,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             }
             'k' => {
                 assert_eq!(self.next(), '[');
-                let did = self.parse_def(ClosureSource);
+                let did = self.parse_def();
                 let substs = self.parse_substs();
                 let mut tys = vec![];
                 while self.peek() != '.' {
@@ -484,9 +452,9 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
         ty::TypeAndMut { ty: self.parse_ty(), mutbl: m }
     }
 
-    fn parse_def(&mut self, source: DefIdSource) -> DefId {
+    fn parse_def(&mut self) -> DefId {
         let def_id = parse_defid(self.scan(|c| c == '|'));
-        return (self.conv_def_id)(source, def_id);
+        return (self.conv_def_id)(def_id);
     }
 
     fn parse_uint(&mut self) -> usize {
@@ -576,7 +544,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
             'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(),
             'w' => ty::Predicate::WellFormed(self.parse_ty()),
             'O' => {
-                let def_id = self.parse_def(NominalType);
+                let def_id = self.parse_def();
                 assert_eq!(self.next(), '|');
                 ty::Predicate::ObjectSafe(def_id)
             }
@@ -596,12 +564,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
 
     pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
         let name = self.parse_name(':');
-        let def_id = self.parse_def(NominalType);
+        let def_id = self.parse_def();
         let space = self.parse_param_space();
         assert_eq!(self.next(), '|');
         let index = self.parse_u32();
         assert_eq!(self.next(), '|');
-        let default_def_id = self.parse_def(NominalType);
+        let default_def_id = self.parse_def();
         let default = self.parse_opt(|this| this.parse_ty());
         let object_lifetime_default = self.parse_object_lifetime_default();
 
@@ -618,7 +586,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
 
     pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
         let name = self.parse_name(':');
-        let def_id = self.parse_def(NominalType);
+        let def_id = self.parse_def();
         let space = self.parse_param_space();
         assert_eq!(self.next(), '|');
         let index = self.parse_u32();
@@ -726,11 +694,12 @@ fn parse_defid(buf: &[u8]) -> DefId {
     let def_num = match str::from_utf8(def_part).ok().and_then(|s| {
         s.parse::<usize>().ok()
     }) {
-        Some(dn) => dn as ast::NodeId,
+        Some(dn) => dn,
         None => panic!("internal error: parse_defid: id expected, found {:?}",
                        def_part)
     };
-    DefId { krate: crate_num, node: def_num }
+    let index = DefIndex::new(def_num);
+    DefId { krate: crate_num, index: index }
 }
 
 fn parse_unsafety(c: char) -> hir::Unsafety {
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index 4a9257b60c4..1b993a00e28 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -254,7 +254,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
         }
         ty::ReEarlyBound(ref data) => {
             mywrite!(w, "B[{}|{}|{}|{}]",
-                     data.param_id,
+                     (cx.ds)(data.def_id),
                      data.space.to_uint(),
                      data.index,
                      data.name);
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 75826c69036..40e89b39088 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -24,14 +24,12 @@ use metadata::decoder;
 use metadata::encoder as e;
 use metadata::inline::{InlinedItem, InlinedItemRef};
 use metadata::tydecode;
-use metadata::tydecode::{DefIdSource, NominalType, TypeWithId};
-use metadata::tydecode::{RegionParameter, ClosureSource};
 use metadata::tyencode;
 use middle::ty::adjustment;
 use middle::ty::cast;
 use middle::check_const::ConstQualif;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::privacy::{AllPublic, LastMod};
 use middle::region;
 use middle::subst;
@@ -71,10 +69,6 @@ trait tr {
     fn tr(&self, dcx: &DecodeContext) -> Self;
 }
 
-trait tr_intern {
-    fn tr_intern(&self, dcx: &DecodeContext) -> DefId;
-}
-
 // ______________________________________________________________________
 // Top-level methods.
 
@@ -128,10 +122,13 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> {
 pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
                                  tcx: &ty::ctxt<'tcx>,
                                  path: Vec<ast_map::PathElem>,
-                                 par_doc: rbml::Doc)
-                                 -> Result<&'tcx InlinedItem, Vec<ast_map::PathElem>> {
+                                 def_path: ast_map::DefPath,
+                                 par_doc: rbml::Doc,
+                                 orig_did: DefId)
+                                 -> Result<&'tcx InlinedItem, (Vec<ast_map::PathElem>,
+                                                               ast_map::DefPath)> {
     match par_doc.opt_child(c::tag_ast) {
-      None => Err(path),
+      None => Err((path, def_path)),
       Some(ast_doc) => {
         let mut path_as_str = None;
         debug!("> Decoding inlined fn: {:?}::?",
@@ -152,7 +149,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
             last_filemap_index: Cell::new(0)
         };
         let raw_ii = decode_ast(ast_doc);
-        let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, raw_ii, dcx);
+        let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx);
 
         let name = match *ii {
             InlinedItem::Item(ref i) => i.name,
@@ -166,7 +163,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
                name);
         region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii);
         decode_side_tables(dcx, ast_doc);
-        copy_item_types(dcx, ii);
+        copy_item_types(dcx, ii, orig_did);
         match *ii {
           InlinedItem::Item(ref i) => {
             debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<",
@@ -205,17 +202,6 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
         (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min))
     }
 
-    /// Gets the original crate's DefId from a translated internal
-    /// def-id.
-    pub fn reverse_tr_id(&self, id: ast::NodeId) -> DefId {
-        // from_id_range should be non-empty
-        assert!(!self.from_id_range.empty());
-        // Use wrapping arithmetic because otherwise it introduces control flow.
-        // Maybe we should just have the control flow? -- aatch
-        let node = id.wrapping_sub(self.to_id_range.min).wrapping_add(self.from_id_range.min);
-        DefId { krate: self.cdata.cnum, node: node }
-    }
-
     /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded
     /// data to the current crate numbers..  By external, I mean that it be translated to a
     /// reference to the item in its original crate, as opposed to being translated to a reference
@@ -224,24 +210,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
     /// be inlined.  Note that even when the inlined function is referencing itself recursively, we
     /// would want `tr_def_id` for that reference--- conceptually the function calls the original,
     /// non-inlined version, and trans deals with linking that recursive call to the inlined copy.
-    ///
-    /// However, there are a *few* cases where def-ids are used but we know that the thing being
-    /// referenced is in fact *internal* to the item being inlined.  In those cases, you should use
-    /// `tr_intern_def_id()` below.
     pub fn tr_def_id(&self, did: DefId) -> DefId {
-
         decoder::translate_def_id(self.cdata, did)
     }
 
-    /// Translates an INTERNAL def-id, meaning a def-id that is
-    /// known to refer to some part of the item currently being
-    /// inlined.  In that case, we want to convert the def-id to
-    /// refer to the current crate and to the new, inlined node-id.
-    pub fn tr_intern_def_id(&self, did: DefId) -> DefId {
-        assert_eq!(did.krate, LOCAL_CRATE);
-        DefId { krate: LOCAL_CRATE, node: self.tr_id(did.node) }
-    }
-
     /// Translates a `Span` from an extern crate to the corresponding `Span`
     /// within the local crate's codemap. `creader::import_codemap()` will
     /// already have allocated any additionally needed FileMaps in the local
@@ -300,12 +272,6 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
     }
 }
 
-impl tr_intern for DefId {
-    fn tr_intern(&self, dcx: &DecodeContext) -> DefId {
-        dcx.tr_intern_def_id(*self)
-    }
-}
-
 impl tr for DefId {
     fn tr(&self, dcx: &DecodeContext) -> DefId {
         dcx.tr_def_id(*self)
@@ -471,7 +437,11 @@ impl tr for def::Def {
           def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
           def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
           def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)),
-          def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
+          def::DefLocal(_, nid) => {
+              let nid = dcx.tr_id(nid);
+              let did = dcx.tcx.map.local_def_id(nid);
+              def::DefLocal(did, nid)
+          }
           def::DefVariant(e_did, v_did, is_s) => {
             def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
           },
@@ -482,11 +452,13 @@ impl tr for def::Def {
           def::DefPrimTy(p) => def::DefPrimTy(p),
           def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
           def::DefUse(did) => def::DefUse(did.tr(dcx)),
-          def::DefUpvar(nid1, index, nid2) => {
-            def::DefUpvar(dcx.tr_id(nid1), index, dcx.tr_id(nid2))
+          def::DefUpvar(_, nid1, index, nid2) => {
+              let nid1 = dcx.tr_id(nid1);
+              let nid2 = dcx.tr_id(nid2);
+              let did1 = dcx.tcx.map.local_def_id(nid1);
+              def::DefUpvar(did1, nid1, index, nid2)
           }
           def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
-          def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)),
           def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid))
         }
     }
@@ -579,10 +551,6 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
     }
 }
 
-pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
-    kind.encode(ebml_w).unwrap();
-}
-
 pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
     kind.encode(ebml_w).unwrap();
 }
@@ -606,8 +574,6 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> {
 }
 
 trait rbml_writer_helpers<'tcx> {
-    fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
-                             closure_type: &ty::ClosureTy<'tcx>);
     fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
@@ -630,14 +596,6 @@ trait rbml_writer_helpers<'tcx> {
 }
 
 impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
-    fn emit_closure_type<'b>(&mut self,
-                             ecx: &e::EncodeContext<'b, 'tcx>,
-                             closure_type: &ty::ClosureTy<'tcx>) {
-        self.emit_opaque(|this| {
-            Ok(e::write_closure_type(ecx, this, closure_type))
-        });
-    }
-
     fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) {
         self.emit_opaque(|this| Ok(e::write_region(ecx, this, r)));
     }
@@ -866,7 +824,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
             rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
                 rbml_w.id(id);
 
-                let var_id = freevar.def.def_id().node;
+                let var_id = freevar.def.var_id();
                 let upvar_id = ty::UpvarId {
                     var_id: var_id,
                     closure_expr_id: id
@@ -914,20 +872,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         })
     }
 
-    if let Some(closure_type) = tcx.tables.borrow().closure_tys.get(&DefId::local(id)) {
-        rbml_w.tag(c::tag_table_closure_tys, |rbml_w| {
-            rbml_w.id(id);
-            rbml_w.emit_closure_type(ecx, closure_type);
-        })
-    }
-
-    if let Some(closure_kind) = tcx.tables.borrow().closure_kinds.get(&DefId::local(id)) {
-        rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| {
-            rbml_w.id(id);
-            encode_closure_kind(rbml_w, *closure_kind)
-        })
-    }
-
     if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
         rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
             rbml_w.id(id);
@@ -979,17 +923,12 @@ trait rbml_decoder_decoder_helpers<'tcx> {
                                     -> adjustment::AutoAdjustment<'tcx>;
     fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                  -> cast::CastKind;
-    fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                                 -> ty::ClosureKind;
-    fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-                               -> ty::ClosureTy<'tcx>;
     fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                                    -> adjustment::AutoDerefRef<'tcx>;
     fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
                             -> adjustment::AutoRef<'tcx>;
     fn convert_def_id(&mut self,
                       dcx: &DecodeContext,
-                      source: DefIdSource,
                       did: DefId)
                       -> DefId;
 
@@ -1013,7 +952,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         self.read_opaque(|_, doc| {
             Ok(
                 tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                                              &mut |_, id| decoder::translate_def_id(cdata, id))
+                                              &mut |id| decoder::translate_def_id(cdata, id))
                     .parse_ty())
         }).unwrap()
     }
@@ -1035,7 +974,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         self.read_opaque(|_, doc| {
             Ok(
                 tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                                              &mut |_, id| decoder::translate_def_id(cdata, id))
+                                              &mut |id| decoder::translate_def_id(cdata, id))
                     .parse_substs())
         }).unwrap()
     }
@@ -1048,7 +987,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
             Ok(op(
                 &mut tydecode::TyDecoder::with_doc(
                     dcx.tcx, dcx.cdata.cnum, doc,
-                    &mut |s, a| this.convert_def_id(dcx, s, a))))
+                    &mut |a| this.convert_def_id(dcx, a))))
         }).unwrap();
 
         fn type_string(doc: rbml::Doc) -> String {
@@ -1101,7 +1040,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                            -> subst::Substs<'tcx> {
         self.read_opaque(|this, doc| {
             Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc,
-                                             &mut |s, a| this.convert_def_id(dcx, s, a))
+                                             &mut |a| this.convert_def_id(dcx, a))
                .parse_substs())
         }).unwrap()
     }
@@ -1208,18 +1147,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         Decodable::decode(self).unwrap()
     }
 
-    fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-                                 -> ty::ClosureKind
-    {
-        Decodable::decode(self).unwrap()
-    }
-
-    fn read_closure_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-                               -> ty::ClosureTy<'tcx>
-    {
-        self.read_ty_encoded(dcx, |decoder| decoder.parse_closure_ty())
-    }
-
     /// Converts a def-id that appears in a type.  The correct
     /// translation will depend on what kind of def-id this is.
     /// This is a subtle point: type definitions are not
@@ -1254,14 +1181,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
     /// def-ids so that all these distinctions were unnecessary.
     fn convert_def_id(&mut self,
                       dcx: &DecodeContext,
-                      source: tydecode::DefIdSource,
                       did: DefId)
                       -> DefId {
-        let r = match source {
-            NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did),
-            ClosureSource => dcx.tr_intern_def_id(did)
-        };
-        debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r);
+        let r = dcx.tr_def_id(did);
+        debug!("convert_def_id(did={:?})={:?}", did, r);
         return r;
     }
 }
@@ -1339,18 +1262,6 @@ fn decode_side_tables(dcx: &DecodeContext,
                             val_dsr.read_auto_adjustment(dcx);
                         dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj);
                     }
-                    c::tag_table_closure_tys => {
-                        let closure_ty =
-                            val_dsr.read_closure_ty(dcx);
-                        dcx.tcx.tables.borrow_mut().closure_tys.insert(DefId::local(id),
-                                                                closure_ty);
-                    }
-                    c::tag_table_closure_kinds => {
-                        let closure_kind =
-                            val_dsr.read_closure_kind(dcx);
-                        dcx.tcx.tables.borrow_mut().closure_kinds.insert(DefId::local(id),
-                                                                  closure_kind);
-                    }
                     c::tag_table_cast_kinds => {
                         let cast_kind =
                             val_dsr.read_cast_kind(dcx);
@@ -1375,10 +1286,11 @@ fn decode_side_tables(dcx: &DecodeContext,
 
 // copy the tcache entries from the original item to the new
 // inlined item
-fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem) {
-    fn copy_item_type(dcx: &DecodeContext, inlined_node: ast::NodeId) {
-        let inlined_did = DefId::local(inlined_node);
-        let remote_did = dcx.reverse_tr_id(inlined_node);
+fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) {
+    fn copy_item_type(dcx: &DecodeContext,
+                      inlined_id: ast::NodeId,
+                      remote_did: DefId) {
+        let inlined_did = dcx.tcx.map.local_def_id(inlined_id);
         dcx.tcx.register_item_type(inlined_did,
                                    dcx.tcx.lookup_item_type(remote_did));
 
@@ -1390,19 +1302,25 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem) {
         &InlinedItem::ImplItem(_, ref ii) => ii.id,
         &InlinedItem::Foreign(ref fi) => fi.id
     };
-    copy_item_type(dcx, item_node_id);
+    copy_item_type(dcx, item_node_id, orig_did);
 
     // copy the entries of inner items
     if let &InlinedItem::Item(ref item) = ii {
         match item.node {
             hir::ItemEnum(ref def, _) => {
-                for variant in &def.variants {
-                    copy_item_type(dcx, variant.node.id);
+                let orig_def = dcx.tcx.lookup_adt_def(orig_did);
+                for (i_variant, orig_variant) in
+                    def.variants.iter().zip(orig_def.variants.iter())
+                {
+                    copy_item_type(dcx, i_variant.node.id, orig_variant.did);
                 }
             }
             hir::ItemStruct(ref def, _) => {
                 if let Some(ctor_id) = def.ctor_id {
-                    copy_item_type(dcx, ctor_id);
+                    let ctor_did = dcx.tcx.lookup_adt_def(orig_did)
+                        .struct_variant().ctor_id;
+                    println!("copying ctor {:?}", ctor_did);
+                    copy_item_type(dcx, ctor_id, ctor_did);
                 }
             }
             _ => {}
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index b5901762e30..15c56d23da2 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -659,7 +659,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                                              doesn't point to a constant");
                     }
                 }
-                Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
+                Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {
                     // Sadly, we can't determine whether the types are zero-sized.
                     v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
                 }
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 40d7b63cff9..283c6264717 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -245,7 +245,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
                 let pat_ty = cx.tcx.pat_ty(p);
                 if let ty::TyEnum(edef, _) = pat_ty.sty {
                     let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
-                    if let Some(DefLocal(_)) = def {
+                    if let Some(DefLocal(..)) = def {
                         if edef.variants.iter().any(|variant|
                             variant.name == ident.node.name
                                 && variant.kind() == VariantKind::Unit
diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs
index 942d8313ec2..acb66b8efe7 100644
--- a/src/librustc/middle/check_static_recursion.rs
+++ b/src/librustc/middle/check_static_recursion.rs
@@ -240,37 +240,43 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
                 match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
                     Some(DefStatic(def_id, _)) |
                     Some(DefAssociatedConst(def_id)) |
-                    Some(DefConst(def_id)) if def_id.is_local() => {
-                        match self.ast_map.get(def_id.node) {
-                          ast_map::NodeItem(item) =>
-                            self.visit_item(item),
-                          ast_map::NodeTraitItem(item) =>
-                            self.visit_trait_item(item),
-                          ast_map::NodeImplItem(item) =>
-                            self.visit_impl_item(item),
-                          ast_map::NodeForeignItem(_) => {},
-                          _ => {
-                              self.sess.span_bug(
-                                  e.span,
-                                  &format!("expected item, found {}",
-                                           self.ast_map.node_to_string(def_id.node)));
-                          }
+                    Some(DefConst(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),
+                                ast_map::NodeTraitItem(item) =>
+                                    self.visit_trait_item(item),
+                                ast_map::NodeImplItem(item) =>
+                                    self.visit_impl_item(item),
+                                ast_map::NodeForeignItem(_) => {},
+                                _ => {
+                                    self.sess.span_bug(
+                                        e.span,
+                                        &format!("expected item, found {}",
+                                                 self.ast_map.node_to_string(node_id)));
+                                }
+                            }
                         }
                     }
                     // For variants, we only want to check expressions that
                     // affect the specific variant used, but we need to check
                     // the whole enum definition to see what expression that
                     // might be (if any).
-                    Some(DefVariant(enum_id, variant_id, false)) if enum_id.is_local() => {
-                        if let hir::ItemEnum(ref enum_def, ref generics) =
-                               self.ast_map.expect_item(enum_id.local_id()).node {
-                            self.populate_enum_discriminants(enum_def);
-                            let variant = self.ast_map.expect_variant(variant_id.local_id());
-                            self.visit_variant(variant, generics);
-                        } else {
-                            self.sess.span_bug(e.span,
-                                "`check_static_recursion` found \
-                                 non-enum in DefVariant");
+                    Some(DefVariant(enum_id, variant_id, false)) => {
+                        if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
+                            if let hir::ItemEnum(ref enum_def, ref generics) =
+                                self.ast_map.expect_item(enum_node_id).node
+                            {
+                                self.populate_enum_discriminants(enum_def);
+                                let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
+                                let variant = self.ast_map.expect_variant(variant_id);
+                                self.visit_variant(variant, generics);
+                            } else {
+                                self.sess.span_bug(e.span,
+                                                   "`check_static_recursion` found \
+                                                    non-enum in DefVariant");
+                            }
                         }
                     }
                     _ => ()
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 4894a78f1ac..06ec176c30e 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -69,41 +69,20 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
         None
     }
 
-    if enum_def.is_local() {
-        match tcx.map.find(enum_def.node) {
+    if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
+        let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
+        match tcx.map.find(enum_node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
                 hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
-                    variant_expr(&variants[..], variant_def.node)
+                    variant_expr(&variants[..], variant_node_id)
                 }
                 _ => None
             },
             Some(_) => None
         }
     } else {
-        match tcx.extern_const_variants.borrow().get(&variant_def) {
-            Some(&ast::DUMMY_NODE_ID) => return None,
-            Some(&expr_id) => {
-                return Some(tcx.map.expect_expr(expr_id));
-            }
-            None => {}
-        }
-        let expr_id = match csearch::maybe_get_item_ast(tcx, enum_def,
-            Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
-            csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
-                hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
-                    // NOTE this doesn't do the right thing, it compares inlined
-                    // NodeId's to the original variant_def's NodeId, but they
-                    // come from different crates, so they will likely never match.
-                    variant_expr(&variants[..], variant_def.node).map(|e| e.id)
-                }
-                _ => None
-            },
-            _ => None
-        };
-        tcx.extern_const_variants.borrow_mut().insert(variant_def,
-                                                      expr_id.unwrap_or(ast::DUMMY_NODE_ID));
-        expr_id.map(|id| tcx.map.expect_expr(id))
+        None
     }
 }
 
@@ -111,8 +90,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                                         def_id: DefId,
                                         maybe_ref_id: Option<ast::NodeId>)
                                         -> Option<&'tcx Expr> {
-    if def_id.is_local() {
-        match tcx.map.find(def_id.node) {
+    if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+        match tcx.map.find(node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
                 hir::ItemConst(_, ref const_expr) => {
@@ -164,7 +143,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
         }
         let mut used_ref_id = false;
         let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
-            Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
+            Box::new(astencode::decode_inlined_item)) {
             csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
                 hir::ItemConst(_, ref const_expr) => Some(const_expr.id),
                 _ => None
@@ -220,7 +199,7 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId)
     }
 
     let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
-        box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
+        box astencode::decode_inlined_item) {
         csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
         csearch::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
         _ => None
@@ -233,14 +212,14 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId)
 pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
                                    -> Option<FnLikeNode<'tcx>>
 {
-    let fn_id = if !def_id.is_local() {
+    let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+        node_id
+    } else {
         if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
             fn_id
         } else {
             return None;
         }
-    } else {
-        def_id.node
     };
 
     let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
@@ -919,8 +898,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
           let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
           let (const_expr, const_ty) = match opt_def {
               Some(def::DefConst(def_id)) => {
-                  if def_id.is_local() {
-                      match tcx.map.find(def_id.node) {
+                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+                      match tcx.map.find(node_id) {
                           Some(ast_map::NodeItem(it)) => match it.node {
                               hir::ItemConst(ref ty, ref expr) => {
                                   (Some(&**expr), Some(&**ty))
@@ -934,9 +913,9 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                   }
               }
               Some(def::DefAssociatedConst(def_id)) => {
-                  if def_id.is_local() {
+                  if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
                       match tcx.impl_or_trait_item(def_id).container() {
-                          ty::TraitContainer(trait_id) => match tcx.map.find(def_id.node) {
+                          ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
                               Some(ast_map::NodeTraitItem(ti)) => match ti.node {
                                   hir::ConstTraitItem(ref ty, _) => {
                                       if let ExprTypeChecked = ty_hint {
@@ -954,7 +933,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                               },
                               _ => (None, None)
                           },
-                          ty::ImplContainer(_) => match tcx.map.find(def_id.node) {
+                          ty::ImplContainer(_) => match tcx.map.find(node_id) {
                               Some(ast_map::NodeImplItem(ii)) => match ii.node {
                                   hir::ConstImplItem(ref ty, ref expr) => {
                                       (Some(&**expr), Some(&**ty))
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 92592f049e0..6e31b733254 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -29,17 +29,15 @@ use syntax::attr::{self, AttrMetaMethods};
 // explored. For example, if it's a live NodeItem that is a
 // function, then we should explore its block to check for codes that
 // may need to be marked as live.
-fn should_explore(tcx: &ty::ctxt, def_id: DefId) -> bool {
-    if !def_id.is_local() {
-        return false;
-    }
-
-    match tcx.map.find(def_id.node) {
-        Some(ast_map::NodeItem(..))
-        | Some(ast_map::NodeImplItem(..))
-        | Some(ast_map::NodeForeignItem(..))
-        | Some(ast_map::NodeTraitItem(..)) => true,
-        _ => false
+fn should_explore(tcx: &ty::ctxt, node_id: ast::NodeId) -> bool {
+    match tcx.map.find(node_id) {
+        Some(ast_map::NodeItem(..)) |
+        Some(ast_map::NodeImplItem(..)) |
+        Some(ast_map::NodeForeignItem(..)) |
+        Some(ast_map::NodeTraitItem(..)) =>
+            true,
+        _ =>
+            false
     }
 }
 
@@ -50,7 +48,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> {
     struct_has_extern_repr: bool,
     ignore_non_const_paths: bool,
     inherited_pub_visibility: bool,
-    ignore_variant_stack: Vec<ast::NodeId>,
+    ignore_variant_stack: Vec<DefId>,
 }
 
 impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
@@ -68,10 +66,19 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn check_def_id(&mut self, def_id: DefId) {
-        if should_explore(self.tcx, def_id) {
-            self.worklist.push(def_id.node);
+        if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+            if should_explore(self.tcx, node_id) {
+                self.worklist.push(node_id);
+            }
+            self.live_symbols.insert(node_id);
+        }
+    }
+
+    fn insert_def_id(&mut self, def_id: DefId) {
+        if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+            debug_assert!(!should_explore(self.tcx, node_id));
+            self.live_symbols.insert(node_id);
         }
-        self.live_symbols.insert(def_id.node);
     }
 
     fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
@@ -88,13 +95,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         self.tcx.def_map.borrow().get(id).map(|def| {
             match def.full_def() {
                 def::DefConst(_) | def::DefAssociatedConst(..) => {
-                    self.check_def_id(def.def_id())
+                    self.check_def_id(def.def_id());
                 }
                 _ if self.ignore_non_const_paths => (),
                 def::DefPrimTy(_) => (),
+                def::DefSelfTy(..) => (),
                 def::DefVariant(enum_id, variant_id, _) => {
                     self.check_def_id(enum_id);
-                    if !self.ignore_variant_stack.contains(&variant_id.node) {
+                    if !self.ignore_variant_stack.contains(&variant_id) {
                         self.check_def_id(variant_id);
                     }
                 }
@@ -113,7 +121,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
         if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
-            self.live_symbols.insert(def.struct_variant().field_named(name).did.node);
+            self.insert_def_id(def.struct_variant().field_named(name).did);
         } else {
             self.tcx.sess.span_bug(lhs.span, "named field access on non-struct")
         }
@@ -121,7 +129,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
 
     fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
         if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
-            self.live_symbols.insert(def.struct_variant().fields[idx].did.node);
+            self.insert_def_id(def.struct_variant().fields[idx].did);
         }
     }
 
@@ -137,7 +145,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             if let hir::PatWild(hir::PatWildSingle) = pat.node.pat.node {
                 continue;
             }
-            self.live_symbols.insert(variant.field_named(pat.node.name).did.node);
+            self.insert_def_id(variant.field_named(pat.node.name).did);
         }
     }
 
@@ -469,8 +477,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
     // `ctor_id`. On the other hand, in a statement like
     // `type <ident> <generics> = <ty>;` where <ty> refers to a struct_ctor,
     // DefMap maps <ty> to `id` instead.
-    fn symbol_is_live(&mut self, id: ast::NodeId,
-                      ctor_id: Option<ast::NodeId>) -> bool {
+    fn symbol_is_live(&mut self,
+                      id: ast::NodeId,
+                      ctor_id: Option<ast::NodeId>)
+                      -> bool {
         if self.live_symbols.contains(&id)
            || ctor_id.map_or(false,
                              |ctor| self.live_symbols.contains(&ctor)) {
@@ -481,14 +491,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
         // method of a private type is used, but the type itself is never
         // called directly.
         let impl_items = self.tcx.impl_items.borrow();
-        match self.tcx.inherent_impls.borrow().get(&DefId::local(id)) {
+        match self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
             None => (),
             Some(impl_list) => {
                 for impl_did in impl_list.iter() {
                     for item_did in impl_items.get(impl_did).unwrap().iter() {
-                        if self.live_symbols.contains(&item_did.def_id()
-                                                               .node) {
-                            return true;
+                        if let Some(item_node_id) =
+                                self.tcx.map.as_local_node_id(item_did.def_id()) {
+                            if self.live_symbols.contains(&item_node_id) {
+                                return true;
+                            }
                         }
                     }
                 }
diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs
index 86133aad672..3e8325b8612 100644
--- a/src/librustc/middle/def.rs
+++ b/src/librustc/middle/def.rs
@@ -10,7 +10,7 @@
 
 pub use self::Def::*;
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::privacy::LastPrivate;
 use middle::subst::ParamSpace;
 use util::nodemap::NodeMap;
@@ -29,7 +29,8 @@ pub enum Def {
     DefStatic(DefId, bool /* is_mutbl */),
     DefConst(DefId),
     DefAssociatedConst(DefId),
-    DefLocal(ast::NodeId),
+    DefLocal(DefId, // def id of variable
+             ast::NodeId), // node id of variable
     DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
     DefTy(DefId, bool /* is_enum */),
     DefAssociatedTy(DefId /* trait */, DefId),
@@ -37,7 +38,8 @@ pub enum Def {
     DefPrimTy(hir::PrimTy),
     DefTyParam(ParamSpace, u32, DefId, ast::Name),
     DefUse(DefId),
-    DefUpvar(ast::NodeId,  // id of closed over local
+    DefUpvar(DefId,        // def id of closed over local
+             ast::NodeId,  // node id of closed over local
              usize,        // index in the freevars list of the closure
              ast::NodeId), // expr node that creates the closure
 
@@ -50,7 +52,6 @@ pub enum Def {
     /// - If it's an ExprPath referring to some tuple struct, then DefMap maps
     ///   it to a def whose id is the StructDef.ctor_id.
     DefStruct(DefId),
-    DefRegion(ast::NodeId),
     DefLabel(ast::NodeId),
     DefMethod(DefId),
 }
@@ -114,10 +115,21 @@ pub struct Export {
 }
 
 impl Def {
-    pub fn local_node_id(&self) -> ast::NodeId {
-        let def_id = self.def_id();
-        assert_eq!(def_id.krate, LOCAL_CRATE);
-        def_id.node
+    pub fn var_id(&self) -> ast::NodeId {
+        match *self {
+            DefLocal(_, id) |
+            DefUpvar(_, id, _, _) => {
+                id
+            }
+
+            DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
+            DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
+            DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) |
+            DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
+            DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => {
+                panic!("attempted .def_id() on invalid {:?}", self)
+            }
+        }
     }
 
     pub fn def_id(&self) -> DefId {
@@ -126,19 +138,15 @@ impl Def {
             DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
             DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
             DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
-            DefSelfTy(Some(id), None)=> {
+            DefLocal(id, _) | DefUpvar(id, _, _, _) => {
                 id
             }
-            DefLocal(id) |
-            DefUpvar(id, _, _) |
-            DefRegion(id) |
-            DefLabel(id)  |
-            DefSelfTy(_, Some((_, id))) => {
-                DefId::local(id)
-            }
 
-            DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"),
-            DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"),
+            DefLabel(..)  |
+            DefPrimTy(..) |
+            DefSelfTy(..) => {
+                panic!("attempted .def_id() on invalid def: {:?}", self)
+            }
         }
     }
 
diff --git a/src/librustc/middle/def_id.rs b/src/librustc/middle/def_id.rs
index 2966339f0a4..ba4eac9e9eb 100644
--- a/src/librustc/middle/def_id.rs
+++ b/src/librustc/middle/def_id.rs
@@ -8,21 +8,55 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use metadata::cstore::LOCAL_CRATE;
 use middle::ty;
-use syntax::ast::{CrateNum, NodeId};
+use syntax::ast::CrateNum;
 use std::fmt;
+use std::u32;
 
+/// A DefIndex is an index into the hir-map for a crate, identifying a
+/// particular definition. It should really be considered an interned
+/// shorthand for a particular DefPath.
+#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
+           RustcDecodable, Hash, Copy)]
+pub struct DefIndex(u32);
+
+impl DefIndex {
+    pub fn new(x: usize) -> DefIndex {
+        assert!(x < (u32::MAX as usize));
+        DefIndex(x as u32)
+    }
+
+    pub fn from_u32(x: u32) -> DefIndex {
+        DefIndex(x)
+    }
+
+    pub fn as_usize(&self) -> usize {
+        self.0 as usize
+    }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
+}
+
+/// The crate root is always assigned index 0 by the AST Map code,
+/// thanks to `NodeCollector::new`.
+pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
+
+/// A DefId identifies a particular *definition*, by combining a crate
+/// index and a def index.
 #[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
            RustcDecodable, Hash, Copy)]
 pub struct DefId {
     pub krate: CrateNum,
-    pub node: NodeId,
+    pub index: DefIndex,
 }
 
 impl fmt::Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f, "DefId {{ krate: {}, node: {}",
-                    self.krate, self.node));
+        try!(write!(f, "DefId {{ krate: {:?}, node: {:?}",
+                    self.krate, self.index));
 
         // Unfortunately, there seems to be no way to attempt to print
         // a path for a def-id, so I'll just make a best effort for now
@@ -40,23 +74,11 @@ impl fmt::Debug for DefId {
 
 
 impl DefId {
-    pub fn local(id: NodeId) -> DefId {
-        DefId { krate: LOCAL_CRATE, node: id }
-    }
-
-    /// Read the node id, asserting that this def-id is krate-local.
-    pub fn local_id(&self) -> NodeId {
-        assert_eq!(self.krate, LOCAL_CRATE);
-        self.node
+    pub fn local(index: DefIndex) -> DefId {
+        DefId { krate: LOCAL_CRATE, index: index }
     }
 
     pub fn is_local(&self) -> bool {
         self.krate == LOCAL_CRATE
     }
 }
-
-
-/// Item definitions in the currently-compiled crate would have the CrateNum
-/// LOCAL_CRATE in their DefId.
-pub const LOCAL_CRATE: CrateNum = 0;
-
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 13e8fddf779..1eed7fb95a1 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -276,15 +276,13 @@ enum PassArgs {
 }
 
 impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
-    pub fn new(delegate: &'d mut Delegate<'tcx>,
+    pub fn new(delegate: &'d mut (Delegate<'tcx>),
                typer: &'t infer::InferCtxt<'a, 'tcx>)
                -> ExprUseVisitor<'d,'t,'a,'tcx> where 'tcx:'a
     {
-        ExprUseVisitor {
-            typer: typer,
-            mc: mc::MemCategorizationContext::new(typer),
-            delegate: delegate,
-        }
+        let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> =
+            mc::MemCategorizationContext::new(typer);
+        ExprUseVisitor { typer: typer, mc: mc, delegate: delegate }
     }
 
     pub fn walk_fn(&mut self,
@@ -1160,7 +1158,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
 
         self.tcx().with_freevars(closure_expr.id, |freevars| {
             for freevar in freevars {
-                let id_var = freevar.def.def_id().node;
+                let id_var = freevar.def.var_id();
                 let upvar_id = ty::UpvarId { var_id: id_var,
                                              closure_expr_id: closure_expr.id };
                 let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
@@ -1192,7 +1190,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
                         -> mc::McResult<mc::cmt<'tcx>> {
         // Create the cmt for the variable being borrowed, from the
         // caller's perspective
-        let var_id = upvar_def.def_id().node;
+        let var_id = upvar_def.var_id();
         let var_ty = try!(self.typer.node_ty(var_id));
         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
     }
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 3def56f94a1..3b44dc12ac1 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -1455,7 +1455,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         def_id: DefId)
                         -> Option<ty::ClosureKind>
     {
-        self.tables.borrow().closure_kinds.get(&def_id).cloned()
+        if def_id.is_local() {
+            self.tables.borrow().closure_kinds.get(&def_id).cloned()
+        } else {
+            // During typeck, ALL closures are local. But afterwards,
+            // during trans, we see closure ids from other traits.
+            // That may require loading the closure data out of the
+            // cstore.
+            Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id))
+        }
     }
 
     pub fn closure_type(&self,
@@ -1463,12 +1471,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         substs: &ty::ClosureSubsts<'tcx>)
                         -> ty::ClosureTy<'tcx>
     {
-        let closure_ty = self.tables
-                             .borrow()
-                             .closure_tys
-                             .get(&def_id)
-                             .unwrap()
-                             .subst(self.tcx, &substs.func_substs);
+        let closure_ty =
+            ty::Tables::closure_type(self.tables,
+                                     self.tcx,
+                                     def_id,
+                                     substs);
 
         if self.normalize {
             normalize_associated_type(&self.tcx, &closure_ty)
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 85e51512bca..03c75fc6cc3 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -21,6 +21,7 @@
 
 pub use self::LangItem::*;
 
+use front::map as hir_map;
 use session::Session;
 use metadata::csearch::each_lang_item;
 use middle::def_id::DefId;
@@ -144,21 +145,23 @@ impl LanguageItems {
     )*
 }
 
-struct LanguageItemCollector<'a> {
+struct LanguageItemCollector<'a, 'tcx: 'a> {
     items: LanguageItems,
 
+    ast_map: &'a hir_map::Map<'tcx>,
+
     session: &'a Session,
 
     item_refs: FnvHashMap<&'static str, usize>,
 }
 
-impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> {
+impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let Some(value) = extract(&item.attrs) {
             let item_index = self.item_refs.get(&value[..]).cloned();
 
             if let Some(item_index) = item_index {
-                self.collect_item(item_index, DefId::local(item.id), item.span)
+                self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span)
             }
         }
 
@@ -166,16 +169,18 @@ impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> {
     }
 }
 
-impl<'a> LanguageItemCollector<'a> {
-    pub fn new(session: &'a Session) -> LanguageItemCollector<'a> {
+impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
+    pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>)
+               -> LanguageItemCollector<'a, 'tcx> {
         let mut item_refs = FnvHashMap();
 
         $( item_refs.insert($name, $variant as usize); )*
 
         LanguageItemCollector {
             session: session,
+            ast_map: ast_map,
             items: LanguageItems::new(),
-            item_refs: item_refs
+            item_refs: item_refs,
         }
     }
 
@@ -203,8 +208,8 @@ impl<'a> LanguageItemCollector<'a> {
     pub fn collect_external_language_items(&mut self) {
         let crate_store = &self.session.cstore;
         crate_store.iter_crate_data(|crate_number, _crate_metadata| {
-            each_lang_item(crate_store, crate_number, |node_id, item_index| {
-                let def_id = DefId { krate: crate_number, node: node_id };
+            each_lang_item(crate_store, crate_number, |index, item_index| {
+                let def_id = DefId { krate: crate_number, index: index };
                 self.collect_item(item_index, def_id, DUMMY_SP);
                 true
             });
@@ -230,9 +235,11 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<InternedString> {
     return None;
 }
 
-pub fn collect_language_items(krate: &hir::Crate,
-                              session: &Session) -> LanguageItems {
-    let mut collector = LanguageItemCollector::new(session);
+pub fn collect_language_items(session: &Session,
+                              map: &hir_map::Map)
+                              -> LanguageItems {
+    let krate: &hir::Crate = map.krate();
+    let mut collector = LanguageItemCollector::new(session, map);
     collector.collect(krate);
     let LanguageItemCollector { mut items, .. } = collector;
     weak_lang_items::check_crate(krate, session, &mut items);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f3a3b536951..3b56597d353 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -465,7 +465,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         let mut call_caps = Vec::new();
         ir.tcx.with_freevars(expr.id, |freevars| {
             for fv in freevars {
-                if let DefLocal(rv) = fv.def {
+                if let DefLocal(_, rv) = fv.def {
                     let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
                     call_caps.push(CaptureInfo {ln: fv_ln,
                                                 var_nid: rv});
@@ -1268,7 +1268,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                    -> LiveNode {
         match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
-          DefLocal(nid) => {
+          DefLocal(_, nid) => {
             let ln = self.live_node(expr.id, expr.span);
             if acc != 0 {
                 self.init_from_succ(ln, succ);
@@ -1517,9 +1517,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
             hir::ExprPath(..) => {
-                if let DefLocal(nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
-                                                                   .unwrap()
-                                                                   .full_def() {
+                if let DefLocal(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+                                                                      .unwrap()
+                                                                      .full_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
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2e7d9e89824..555f864befb 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -551,7 +551,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
           }
           def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
           def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
-          def::DefTyParam(..) | def::DefRegion(_) |
+          def::DefTyParam(..) |
           def::DefLabel(_) | def::DefSelfTy(..) |
           def::DefAssociatedTy(..) => {
               Ok(Rc::new(cmt_ {
@@ -575,7 +575,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
               }))
           }
 
-          def::DefUpvar(var_id, _, fn_node_id) => {
+          def::DefUpvar(_, var_id, _, fn_node_id) => {
               let ty = try!(self.node_ty(fn_node_id));
               match ty.sty {
                   ty::TyClosure(closure_id, _) => {
@@ -600,7 +600,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
               }
           }
 
-          def::DefLocal(vid) => {
+          def::DefLocal(_, vid) => {
             Ok(Rc::new(cmt_ {
                 id: id,
                 span: span,
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 0ffa5d7a5e3..48550c3d8b2 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -219,7 +219,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path {
 }
 
 /// Return variants that are necessary to exist for the pattern to match.
-pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<ast::NodeId> {
+pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
     let mut variants = vec![];
     walk_pat(pat, |p| {
         match p.node {
@@ -228,7 +228,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<ast::NodeId> {
             hir::PatStruct(..) => {
                 match dm.borrow().get(&p.id) {
                     Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
-                        variants.push(id.node);
+                        variants.push(id);
                     }
                     _ => ()
                 }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 017c8f1e42b..a89da9704d9 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -17,7 +17,7 @@
 
 use front::map as ast_map;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::ty;
 use middle::privacy;
 use session::config;
@@ -61,20 +61,15 @@ fn method_might_be_inlined(tcx: &ty::ctxt, sig: &hir::MethodSig,
         generics_require_inlining(&sig.generics) {
         return true
     }
-    if impl_src.is_local() {
-        {
-            match tcx.map.find(impl_src.node) {
-                Some(ast_map::NodeItem(item)) => {
-                    item_might_be_inlined(&*item)
-                }
-                Some(..) | None => {
-                    tcx.sess.span_bug(impl_item.span, "impl did is not an item")
-                }
-            }
+    if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_src) {
+        match tcx.map.find(impl_node_id) {
+            Some(ast_map::NodeItem(item)) =>
+                item_might_be_inlined(&*item),
+            Some(..) | None =>
+                tcx.sess.span_bug(impl_item.span, "impl did is not an item")
         }
     } else {
-        tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent \
-                                           of a local method")
+        tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent of a local method")
     }
 }
 
@@ -106,22 +101,22 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
                 };
 
                 let def_id = def.def_id();
-                if def_id.is_local() {
+                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(def_id.node)
+                        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::DefConst(..) | def::DefAssociatedConst(..) => {
-                                self.worklist.push(def_id.node);
+                                self.worklist.push(node_id);
                             }
 
                             // If this wasn't a static, then the destination is
                             // surely reachable.
                             _ => {
-                                self.reachable_symbols.insert(def_id.node);
+                                self.reachable_symbols.insert(node_id);
                             }
                         }
                     }
@@ -132,11 +127,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
                 let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
                 match self.tcx.impl_or_trait_item(def_id).container() {
                     ty::ImplContainer(_) => {
-                        if def_id.is_local() {
+                        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(def_id.node)
+                                self.worklist.push(node_id)
                             }
-                            self.reachable_symbols.insert(def_id.node);
+                            self.reachable_symbols.insert(node_id);
                         }
                     }
                     ty::TraitContainer(_) => {}
@@ -171,11 +166,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // Returns true if the given def ID represents a local item that is
     // eligible for inlining and false otherwise.
     fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
-        if def_id.krate != LOCAL_CRATE {
-            return false
-        }
+        let node_id = match self.tcx.map.as_local_node_id(def_id) {
+            Some(node_id) => node_id,
+            None => { return false; }
+        };
 
-        let node_id = def_id.node;
         match self.tcx.map.find(node_id) {
             Some(ast_map::NodeItem(item)) => {
                 match item.node {
@@ -204,11 +199,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                             // Check the impl. If the generics on the self
                             // type of the impl require inlining, this method
                             // does too.
-                            assert!(impl_did.is_local());
-                            match self.tcx
-                                      .map
-                                      .expect_item(impl_did.node)
-                                      .node {
+                            let impl_node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
+                            match self.tcx.map.expect_item(impl_node_id).node {
                                 hir::ItemImpl(_, _, ref generics, _, _, _) => {
                                     generics_require_inlining(generics)
                                 }
@@ -354,8 +346,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         drop_trait.for_each_impl(self.tcx, |drop_impl| {
             for destructor in &self.tcx.impl_items.borrow()[&drop_impl] {
                 let destructor_did = destructor.def_id();
-                if destructor_did.is_local() {
-                    self.reachable_symbols.insert(destructor_did.node);
+                if let Some(destructor_node_id) = self.tcx.map.as_local_node_id(destructor_did) {
+                    self.reachable_symbols.insert(destructor_node_id);
                 }
             }
         })
@@ -377,8 +369,10 @@ pub fn find_reachable(tcx: &ty::ctxt,
     }
     for (_, item) in tcx.lang_items.items() {
         match *item {
-            Some(did) if did.is_local() => {
-                reachable_context.worklist.push(did.node);
+            Some(did) => {
+                if let Some(node_id) = tcx.map.as_local_node_id(did) {
+                    reachable_context.worklist.push(node_id);
+                }
             }
             _ => {}
         }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 596686f32cb..be227e620b8 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -13,8 +13,9 @@
 
 use session::Session;
 use lint;
+use metadata::cstore::LOCAL_CRATE;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::ty;
 use middle::privacy::PublicItems;
 use metadata::csearch;
@@ -112,7 +113,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                             "An API can't be stabilized after it is deprecated");
                     }
 
-                    self.index.map.insert(DefId::local(id), Some(stab));
+                    let def_id = self.tcx.map.local_def_id(id);
+                    self.index.map.insert(def_id, Some(stab));
 
                     // Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
                     if stab.level != attr::Stable {
@@ -128,7 +130,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                            use_parent, self.parent);
                     if use_parent {
                         if let Some(stab) = self.parent {
-                            self.index.map.insert(DefId::local(id), Some(stab));
+                            let def_id = self.tcx.map.local_def_id(id);
+                            self.index.map.insert(def_id, Some(stab));
                         } else if self.index.staged_api[&LOCAL_CRATE] && required
                             && self.export_map.contains(&id)
                             && !self.tcx.sess.opts.test {
@@ -380,7 +383,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool,
                 Some(cnum) => cnum,
                 None => return,
             };
-            let id = DefId { krate: cnum, node: ast::CRATE_NODE_ID };
+            let id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
             maybe_do_stability_check(tcx, id, item.span, cb);
         }
 
@@ -471,6 +474,7 @@ pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId,
                   cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
     match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
         Some(def::DefPrimTy(..)) => {}
+        Some(def::DefSelfTy(..)) => {}
         Some(def) => {
             maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
         }
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index 87939c45d67..a3795a32afc 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -17,7 +17,8 @@ use super::PredicateObligation;
 use super::project;
 use super::util;
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
 use middle::subst::{Subst, Substs, TypeSpace};
 use middle::ty::{self, ToPolyTraitRef, Ty};
 use middle::infer::{self, InferCtxt};
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 6f422018c13..60f6cffa346 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -37,7 +37,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
 use super::object_safety;
 use super::util;
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener};
 use middle::subst::{Subst, Substs, TypeSpace};
@@ -1719,7 +1719,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
             ty::TyTuple(ref tys) => ok_if(tys.clone()),
 
-            ty::TyClosure(def_id, ref substs) => {
+            ty::TyClosure(_, ref substs) => {
                 // FIXME -- This case is tricky. In the case of by-ref
                 // closures particularly, we need the results of
                 // inference to decide how to reflect the type of each
@@ -1729,7 +1729,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // captures are by value. Really what we ought to do
                 // is reserve judgement and then intertwine this
                 // analysis with closure inference.
-                assert_eq!(def_id.krate, LOCAL_CRATE);
 
                 // Unboxed closures shouldn't be
                 // implicitly copyable
@@ -1863,7 +1862,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 tys.clone()
             }
 
-            ty::TyClosure(def_id, ref substs) => {
+            ty::TyClosure(_, ref substs) => {
                 // FIXME(#27086). We are invariant w/r/t our
                 // substs.func_substs, but we don't see them as
                 // constituent types; this seems RIGHT but also like
@@ -1872,7 +1871,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // OIBIT interact? That is, there is no way to say
                 // "make me invariant with respect to this TYPE, but
                 // do not act as though I can reach it"
-                assert_eq!(def_id.krate, LOCAL_CRATE);
                 substs.upvar_tys.clone()
             }
 
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index 57f04af2ba9..e506e5b2c07 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -16,6 +16,7 @@
 use front::map as ast_map;
 use session::Session;
 use lint;
+use metadata::csearch;
 use middle;
 use middle::def::DefMap;
 use middle::def_id::DefId;
@@ -134,6 +135,40 @@ impl<'tcx> Tables<'tcx> {
             closure_kinds: DefIdMap(),
         }
     }
+
+    pub fn closure_kind(this: &RefCell<Self>,
+                        tcx: &ty::ctxt<'tcx>,
+                        def_id: DefId)
+                        -> ty::ClosureKind {
+        // If this is a local def-id, it should be inserted into the
+        // tables by typeck; else, it will be retreived from
+        // the external crate metadata.
+        if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) {
+            return kind;
+        }
+
+        let kind = csearch::closure_kind(tcx, def_id);
+        this.borrow_mut().closure_kinds.insert(def_id, kind);
+        kind
+    }
+
+    pub fn closure_type(this: &RefCell<Self>,
+                        tcx: &ty::ctxt<'tcx>,
+                        def_id: DefId,
+                        substs: &ClosureSubsts<'tcx>)
+                        -> ty::ClosureTy<'tcx>
+    {
+        // If this is a local def-id, it should be inserted into the
+        // tables by typeck; else, it will be retreived from
+        // the external crate metadata.
+        if let Some(ty) = this.borrow().closure_tys.get(&def_id) {
+            return ty.subst(tcx, &substs.func_substs);
+        }
+
+        let ty = csearch::closure_ty(tcx, def_id);
+        this.borrow_mut().closure_tys.insert(def_id, ty.clone());
+        ty.subst(tcx, &substs.func_substs)
+    }
 }
 
 impl<'tcx> CommonTypes<'tcx> {
@@ -272,7 +307,6 @@ pub struct ctxt<'tcx> {
 
     /// These caches are used by const_eval when decoding external constants.
     pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
-    pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
     pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
 
     pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
@@ -336,19 +370,8 @@ pub struct ctxt<'tcx> {
     /// constitute it.
     pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
 }
-impl<'tcx> ctxt<'tcx> {
-    pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
-        *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
-    }
-
-    pub fn closure_type(&self,
-                        def_id: DefId,
-                        substs: &ClosureSubsts<'tcx>)
-                        -> ty::ClosureTy<'tcx>
-    {
-        self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
-    }
 
+impl<'tcx> ctxt<'tcx> {
     pub fn type_parameter_def(&self,
                               node_id: NodeId)
                               -> ty::TypeParameterDef<'tcx>
@@ -476,7 +499,6 @@ impl<'tcx> ctxt<'tcx> {
             populated_external_types: RefCell::new(DefIdSet()),
             populated_external_primitive_impls: RefCell::new(DefIdSet()),
             extern_const_statics: RefCell::new(DefIdMap()),
-            extern_const_variants: RefCell::new(DefIdMap()),
             extern_const_fns: RefCell::new(DefIdMap()),
             node_lint_levels: RefCell::new(FnvHashMap()),
             transmute_restrictions: RefCell::new(Vec::new()),
diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs
index ba7be3e2c99..61536934aae 100644
--- a/src/librustc/middle/ty/error.rs
+++ b/src/librustc/middle/ty/error.rs
@@ -302,13 +302,15 @@ impl<'tcx> ty::ctxt<'tcx> {
                                              expected.ty,
                                              found.ty));
 
-                match (expected.def_id.is_local(),
-                       self.map.opt_span(expected.def_id.node)) {
-                    (true, Some(span)) => {
+                match
+                    self.map.as_local_node_id(expected.def_id)
+                            .and_then(|node_id| self.map.opt_span(node_id))
+                {
+                    Some(span) => {
                         self.sess.span_note(span,
                                             &format!("a default was defined here..."));
                     }
-                    (_, _) => {
+                    None => {
                         self.sess.note(
                             &format!("a default is defined on `{}`",
                                      self.item_path_str(expected.def_id)));
@@ -319,13 +321,15 @@ impl<'tcx> ty::ctxt<'tcx> {
                     expected.origin_span,
                     &format!("...that was applied to an unconstrained type variable here"));
 
-                match (found.def_id.is_local(),
-                       self.map.opt_span(found.def_id.node)) {
-                    (true, Some(span)) => {
+                match
+                    self.map.as_local_node_id(found.def_id)
+                            .and_then(|node_id| self.map.opt_span(node_id))
+                {
+                    Some(span) => {
                         self.sess.span_note(span,
                                             &format!("a second default was defined here..."));
                     }
-                    (_, _) => {
+                    None => {
                         self.sess.note(
                             &format!("a second default is defined on `{}`",
                                      self.item_path_str(found.def_id)));
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 45522c4e457..fddfb7b583e 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -22,9 +22,10 @@ pub use self::LvaluePreference::*;
 use front::map as ast_map;
 use front::map::LinkedPath;
 use metadata::csearch;
+use metadata::cstore::LOCAL_CRATE;
 use middle;
 use middle::def::{self, ExportMap};
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
@@ -616,7 +617,7 @@ pub struct RegionParameterDef {
 impl RegionParameterDef {
     pub fn to_early_bound_region(&self) -> ty::Region {
         ty::ReEarlyBound(ty::EarlyBoundRegion {
-            param_id: self.def_id.node,
+            def_id: self.def_id,
             space: self.space,
             index: self.index,
             name: self.name,
@@ -1123,7 +1124,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the impl
                         let impl_id = cx.map.get_parent(id);
-                        let impl_def_id = DefId::local(impl_id);
+                        let impl_def_id = cx.map.local_def_id(impl_id);
                         let scheme = cx.lookup_item_type(impl_def_id);
                         let predicates = cx.lookup_predicates(impl_def_id);
                         cx.construct_parameter_environment(impl_item.span,
@@ -1132,7 +1133,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                                            id)
                     }
                     hir::ConstImplItem(_, _) => {
-                        let def_id = DefId::local(id);
+                        let def_id = cx.map.local_def_id(id);
                         let scheme = cx.lookup_item_type(def_id);
                         let predicates = cx.lookup_predicates(def_id);
                         cx.construct_parameter_environment(impl_item.span,
@@ -1141,7 +1142,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                                            id)
                     }
                     hir::MethodImplItem(_, ref body) => {
-                        let method_def_id = DefId::local(id);
+                        let method_def_id = cx.map.local_def_id(id);
                         match cx.impl_or_trait_item(method_def_id) {
                             MethodTraitItem(ref method_ty) => {
                                 let method_generics = &method_ty.generics;
@@ -1167,7 +1168,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the trait
                         let trait_id = cx.map.get_parent(id);
-                        let trait_def_id = DefId::local(trait_id);
+                        let trait_def_id = cx.map.local_def_id(trait_id);
                         let trait_def = cx.lookup_trait_def(trait_def_id);
                         let predicates = cx.lookup_predicates(trait_def_id);
                         cx.construct_parameter_environment(trait_item.span,
@@ -1176,7 +1177,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                                            id)
                     }
                     hir::ConstTraitItem(..) => {
-                        let def_id = DefId::local(id);
+                        let def_id = cx.map.local_def_id(id);
                         let scheme = cx.lookup_item_type(def_id);
                         let predicates = cx.lookup_predicates(def_id);
                         cx.construct_parameter_environment(trait_item.span,
@@ -1189,8 +1190,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         // block, unless this is a trait method with
                         // no default, then fallback to the method id.
                         let body_id = body.as_ref().map(|b| b.id).unwrap_or(id);
-                        let method_def_id = DefId::local(id);
-
+                        let method_def_id = cx.map.local_def_id(id);
                         match cx.impl_or_trait_item(method_def_id) {
                             MethodTraitItem(ref method_ty) => {
                                 let method_generics = &method_ty.generics;
@@ -1215,7 +1215,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                 match item.node {
                     hir::ItemFn(_, _, _, _, _, ref body) => {
                         // We assume this is a function.
-                        let fn_def_id = DefId::local(id);
+                        let fn_def_id = cx.map.local_def_id(id);
                         let fn_scheme = cx.lookup_item_type(fn_def_id);
                         let fn_predicates = cx.lookup_predicates(fn_def_id);
 
@@ -1229,7 +1229,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                     hir::ItemImpl(..) |
                     hir::ItemConst(..) |
                     hir::ItemStatic(..) => {
-                        let def_id = DefId::local(id);
+                        let def_id = cx.map.local_def_id(id);
                         let scheme = cx.lookup_item_type(def_id);
                         let predicates = cx.lookup_predicates(def_id);
                         cx.construct_parameter_environment(item.span,
@@ -1238,7 +1238,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                                            id)
                     }
                     hir::ItemTrait(..) => {
-                        let def_id = DefId::local(id);
+                        let def_id = cx.map.local_def_id(id);
                         let trait_def = cx.lookup_trait_def(def_id);
                         let predicates = cx.lookup_predicates(def_id);
                         cx.construct_parameter_environment(item.span,
@@ -1473,7 +1473,10 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> {
     pub did: DefId,
     pub name: Name, // struct's name if this is a struct
     pub disr_val: Disr,
-    pub fields: Vec<FieldDefData<'tcx, 'container>>
+    pub fields: Vec<FieldDefData<'tcx, 'container>>,
+    /// The DefId of the variant's ctor (unless the variant is a
+    /// tuple-like struct variant, this is just the variant's def-id).
+    pub ctor_id: DefId
 }
 
 pub struct FieldDefData<'tcx, 'container: 'tcx> {
@@ -2100,11 +2103,11 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn provided_trait_methods(&self, id: DefId) -> Vec<Rc<Method<'tcx>>> {
-        if id.is_local() {
-            if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node {
+        if let Some(id) = self.map.as_local_node_id(id) {
+            if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node {
                 ms.iter().filter_map(|ti| {
                     if let hir::MethodTraitItem(_, Some(_)) = ti.node {
-                        match self.impl_or_trait_item(DefId::local(ti.id)) {
+                        match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
                             MethodTraitItem(m) => Some(m),
                             _ => {
                                 self.sess.bug("provided_trait_methods(): \
@@ -2125,12 +2128,12 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn associated_consts(&self, id: DefId) -> Vec<Rc<AssociatedConst<'tcx>>> {
-        if id.is_local() {
-            match self.map.expect_item(id.node).node {
+        if let Some(id) = self.map.as_local_node_id(id) {
+            match self.map.expect_item(id).node {
                 ItemTrait(_, _, _, ref tis) => {
                     tis.iter().filter_map(|ti| {
                         if let hir::ConstTraitItem(_, _) = ti.node {
-                            match self.impl_or_trait_item(DefId::local(ti.id)) {
+                            match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
                                     self.sess.bug("associated_consts(): \
@@ -2146,7 +2149,7 @@ impl<'tcx> ctxt<'tcx> {
                 ItemImpl(_, _, _, _, _, ref iis) => {
                     iis.iter().filter_map(|ii| {
                         if let hir::ConstImplItem(_, _) = ii.node {
-                            match self.impl_or_trait_item(DefId::local(ii.id)) {
+                            match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
                                     self.sess.bug("associated_consts(): \
@@ -2186,8 +2189,8 @@ impl<'tcx> ctxt<'tcx> {
     }
 
     pub fn trait_impl_polarity(&self, id: DefId) -> Option<hir::ImplPolarity> {
-        if id.is_local() {
-            match self.map.find(id.node) {
+        if let Some(id) = self.map.as_local_node_id(id) {
+            match self.map.find(id) {
                 Some(ast_map::NodeItem(item)) => {
                     match item.node {
                         hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
@@ -2242,9 +2245,9 @@ impl<'tcx> ctxt<'tcx> {
 
     /// Returns whether this DefId refers to an impl
     pub fn is_impl(&self, id: DefId) -> bool {
-        if id.is_local() {
+        if let Some(id) = self.map.as_local_node_id(id) {
             if let Some(ast_map::NodeItem(
-                &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id.node) {
+                &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) {
                 true
             } else {
                 false
@@ -2262,19 +2265,27 @@ impl<'tcx> ctxt<'tcx> {
         self.with_path(id, |path| ast_map::path_to_string(path))
     }
 
+    pub fn def_path(&self, id: DefId) -> ast_map::DefPath {
+        if id.is_local() {
+            self.map.def_path(id)
+        } else {
+            csearch::def_path(self, id)
+        }
+    }
+
     pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
         F: FnOnce(ast_map::PathElems) -> T,
     {
-        if id.is_local() {
-            self.map.with_path(id.node, f)
+        if let Some(id) = self.map.as_local_node_id(id) {
+            self.map.with_path(id, f)
         } else {
             f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty()))
         }
     }
 
     pub fn item_name(&self, id: DefId) -> ast::Name {
-        if id.is_local() {
-            self.map.get_path_elem(id.node).name()
+        if let Some(id) = self.map.as_local_node_id(id) {
+            self.map.get_path_elem(id).name()
         } else {
             csearch::get_item_name(self, id)
         }
@@ -2334,8 +2345,8 @@ impl<'tcx> ctxt<'tcx> {
 
     /// Get the attributes of a definition.
     pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> {
-        if did.is_local() {
-            Cow::Borrowed(self.map.attrs(did.node))
+        if let Some(id) = self.map.as_local_node_id(did) {
+            Cow::Borrowed(self.map.attrs(id))
         } else {
             Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did))
         }
@@ -2479,6 +2490,18 @@ impl<'tcx> ctxt<'tcx> {
         def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
     }
 
+    pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
+        Tables::closure_kind(&self.tables, self, def_id)
+    }
+
+    pub fn closure_type(&self,
+                        def_id: DefId,
+                        substs: &ClosureSubsts<'tcx>)
+                        -> ty::ClosureTy<'tcx>
+    {
+        Tables::closure_type(&self.tables, self, def_id, substs)
+    }
+
     /// Given the def_id of an impl, return the def_id of the trait it implements.
     /// If it implements no trait, return `None`.
     pub fn trait_id_of_impl(&self, def_id: DefId) -> Option<DefId> {
diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs
index 44f97a6b9e3..c6debc38227 100644
--- a/src/librustc/middle/ty/sty.rs
+++ b/src/librustc/middle/ty/sty.rs
@@ -23,7 +23,7 @@ use std::fmt;
 use std::ops;
 use std::mem;
 use syntax::abi;
-use syntax::ast::{self, Name, NodeId};
+use syntax::ast::{self, Name};
 use syntax::parse::token::special_idents;
 
 use rustc_front::hir;
@@ -675,7 +675,7 @@ pub enum Region {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub struct EarlyBoundRegion {
-    pub param_id: NodeId,
+    pub def_id: DefId,
     pub space: subst::ParamSpace,
     pub index: u32,
     pub name: Name,
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index a431bbaeeb8..b546438f392 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -461,7 +461,7 @@ impl<'tcx> ty::ctxt<'tcx> {
                     tcx.sess.cstore.get_crate_hash(did.krate)
                 };
                 h.as_str().hash(state);
-                did.node.hash(state);
+                did.index.hash(state);
             };
             let mt = |state: &mut SipHasher, mt: TypeAndMut| {
                 mt.mutbl.hash(state);
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 68bfa42f6f6..67ced5d3259 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -27,7 +27,7 @@ use std::fmt;
 use syntax::abi;
 use syntax::ast;
 use syntax::parse::token;
-use syntax::ast::DUMMY_NODE_ID;
+use syntax::ast::CRATE_NODE_ID;
 use rustc_front::hir;
 
 pub fn verbose() -> bool {
@@ -232,7 +232,7 @@ fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
             ty::BrEnv => {
                 let name = token::intern("'r");
                 let _ = write!(f, "{}", name);
-                ty::BrNamed(DefId::local(DUMMY_NODE_ID), name)
+                ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID), name)
             }
         })
     }).0;
@@ -309,18 +309,18 @@ impl<'tcx> fmt::Display for ty::TraitTy<'tcx> {
 
 impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeParameterDef({}, {}:{}, {:?}/{})",
+        write!(f, "TypeParameterDef({}, {:?}, {:?}/{})",
                self.name,
-               self.def_id.krate, self.def_id.node,
+               self.def_id,
                self.space, self.index)
     }
 }
 
 impl fmt::Debug for ty::RegionParameterDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "RegionParameterDef({}, {}:{}, {:?}/{}, {:?})",
+        write!(f, "RegionParameterDef({}, {:?}, {:?}/{}, {:?})",
                self.name,
-               self.def_id.krate, self.def_id.node,
+               self.def_id,
                self.space, self.index,
                self.bounds)
     }
@@ -455,7 +455,7 @@ impl fmt::Debug for ty::BoundRegion {
             BrAnon(n) => write!(f, "BrAnon({:?})", n),
             BrFresh(n) => write!(f, "BrFresh({:?})", n),
             BrNamed(did, name) => {
-                write!(f, "BrNamed({}:{}, {:?})", did.krate, did.node, name)
+                write!(f, "BrNamed({:?}, {:?})", did, name)
             }
             BrEnv => "BrEnv".fmt(f),
         }
@@ -466,8 +466,8 @@ impl fmt::Debug for ty::Region {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::ReEarlyBound(ref data) => {
-                write!(f, "ReEarlyBound({}, {:?}, {}, {})",
-                       data.param_id,
+                write!(f, "ReEarlyBound({:?}, {:?}, {}, {})",
+                       data.def_id,
                        data.space,
                        data.index,
                        data.name)
@@ -888,15 +888,15 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             TyTrait(ref data) => write!(f, "{}", data),
             ty::TyProjection(ref data) => write!(f, "{}", data),
             TyStr => write!(f, "str"),
-            TyClosure(ref did, ref substs) => ty::tls::with(|tcx| {
+            TyClosure(did, ref substs) => ty::tls::with(|tcx| {
                 try!(write!(f, "[closure"));
 
-                if did.is_local() {
-                    try!(write!(f, "@{:?}", tcx.map.span(did.node)));
+                if let Some(node_id) = tcx.map.as_local_node_id(did) {
+                    try!(write!(f, "@{:?}", tcx.map.span(node_id)));
                     let mut sep = " ";
-                    try!(tcx.with_freevars(did.node, |freevars| {
+                    try!(tcx.with_freevars(node_id, |freevars| {
                         for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) {
-                            let node_id = freevar.def.local_node_id();
+                            let node_id = freevar.def.var_id();
                             try!(write!(f,
                                         "{}{}:{}",
                                         sep,
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index cecbeacadec..175bac01daa 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -20,7 +20,7 @@ use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
 use borrowck::LoanPathElem::{LpDeref, LpInterior};
 use borrowck::move_data::InvalidMovePathIndex;
 use borrowck::move_data::{MoveData, MovePathIndex};
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::middle::def_id::{DefId};
 use rustc::middle::ty;
 use rustc::middle::mem_categorization as mc;
 
@@ -133,7 +133,7 @@ pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt,
     }
 
     let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
-    let fn_did = DefId { krate: LOCAL_CRATE, node: id };
+    let fn_did = this.tcx.map.local_def_id(id);
     let prev = fraginfo_map.insert(fn_did, fragment_infos);
     assert!(prev.is_none());
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index ce04a5befd9..d004d557856 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -661,7 +661,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
          LocalCrateReader::new(&sess, &ast_map).read_crates(krate));
 
     let lang_items = time(time_passes, "language item collection", ||
-                          middle::lang_items::collect_language_items(krate, &sess));
+                          middle::lang_items::collect_language_items(&sess, &ast_map));
 
     let resolve::CrateMap {
         def_map,
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index cf98b1bd8fd..dc550bb698f 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -130,7 +130,7 @@ fn test_env<F>(source_string: &str,
     let krate = ast_map.krate();
 
     // run just enough stuff to build a tcx:
-    let lang_items = lang_items::collect_language_items(krate, &sess);
+    let lang_items = lang_items::collect_language_items(&sess, &ast_map);
     let resolve::CrateMap { def_map, freevars, .. } =
         resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No);
     let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
@@ -295,7 +295,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     {
         let name = token::intern(name);
         ty::ReEarlyBound(ty::EarlyBoundRegion {
-            param_id: ast::DUMMY_NODE_ID,
+            def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID),
             space: space,
             index: index,
             name: name
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 51b2d58a581..91d1d398a0e 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use middle::def;
-use middle::def_id::DefId;
 use middle::ty;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
@@ -29,7 +28,8 @@ pub enum MethodLateContext {
 }
 
 pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
-    match cx.tcx.impl_or_trait_items.borrow().get(&DefId::local(id)) {
+    let def_id = cx.tcx.map.local_def_id(id);
+    match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
         None => cx.sess().span_bug(span, "missing method descriptor?!"),
         Some(item) => match item.container() {
             ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
@@ -274,7 +274,7 @@ impl LateLintPass for NonSnakeCase {
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
         if let &hir::PatIdent(_, ref path1, _) = &p.node {
             let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
-            if let Some(def::DefLocal(_)) = def {
+            if let Some(def::DefLocal(..)) = def {
                 self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
             }
         }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 90f877b29a1..1df3c1609b8 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -202,10 +202,12 @@ impl LateLintPass for RawPointerDerive {
             }
             _ => return,
         };
-        if !did.is_local() {
+        let node_id = if let Some(node_id) = cx.tcx.map.as_local_node_id(did) {
+            node_id
+        } else {
             return;
-        }
-        let item = match cx.tcx.map.find(did.node) {
+        };
+        let item = match cx.tcx.map.find(node_id) {
             Some(hir_map::NodeItem(item)) => item,
             _ => return,
         };
@@ -246,7 +248,11 @@ impl LateLintPass for NonShorthandFieldPatterns {
                     return false;
                 }
                 let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
-                def == Some(def::DefLocal(fieldpat.node.pat.id))
+                if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) {
+                    def == Some(def::DefLocal(def_id, fieldpat.node.pat.id))
+                } else {
+                    false
+                }
             });
             for fieldpat in field_pats {
                 if let hir::PatIdent(_, ident, None) = fieldpat.node.pat.node {
@@ -458,13 +464,15 @@ impl LateLintPass for MissingDoc {
                 // 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.trait_ref_to_def_id(trait_ref);
-                match cx.tcx.map.find(real_trait.node) {
-                    Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
-                        for itm in impl_items {
-                            self.private_traits.insert(itm.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)) => if item.vis == hir::Visibility::Inherited {
+                            for itm in impl_items {
+                                self.private_traits.insert(itm.id);
+                            }
+                        },
+                        _ => { }
+                    }
                 }
                 return
             },
@@ -555,7 +563,7 @@ impl LateLintPass for MissingCopyImplementations {
                 if ast_generics.is_parameterized() {
                     return;
                 }
-                let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+                let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
                 (def, cx.tcx.mk_struct(def,
                                        cx.tcx.mk_substs(Substs::empty())))
             }
@@ -563,7 +571,7 @@ impl LateLintPass for MissingCopyImplementations {
                 if ast_generics.is_parameterized() {
                     return;
                 }
-                let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+                let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
                 (def, cx.tcx.mk_enum(def,
                                      cx.tcx.mk_substs(Substs::empty())))
             }
@@ -629,9 +637,11 @@ impl LateLintPass for MissingDebugImplementations {
             let debug_def = cx.tcx.lookup_trait_def(debug);
             let mut impls = NodeSet();
             debug_def.for_each_impl(cx.tcx, |d| {
-                if d.is_local() {
-                    if let Some(ty_def) = cx.tcx.node_id_to_type(d.node).ty_to_def_id() {
-                        impls.insert(ty_def.node);
+                if let Some(n) = cx.tcx.map.as_local_node_id(d) {
+                    if let Some(ty_def) = cx.tcx.node_id_to_type(n).ty_to_def_id() {
+                        if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) {
+                            impls.insert(node_id);
+                        }
                     }
                 }
             });
@@ -764,7 +774,7 @@ impl LateLintPass for UnconditionalRecursion {
         let method = match fn_kind {
             FnKind::ItemFn(..) => None,
             FnKind::Method(..) => {
-                cx.tcx.impl_or_trait_item(DefId::local(id)).as_opt_method()
+                cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
             }
             // closures can't recur, so they don't matter.
             FnKind::Closure => return
@@ -877,8 +887,11 @@ impl LateLintPass for UnconditionalRecursion {
                                   id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    tcx.def_map.borrow().get(&callee.id)
-                        .map_or(false, |def| def.def_id() == DefId::local(fn_id))
+                    tcx.def_map
+                       .borrow()
+                       .get(&callee.id)
+                       .map_or(false,
+                               |def| def.def_id() == tcx.map.local_def_id(fn_id))
                 }
                 _ => false
             }
@@ -888,20 +901,22 @@ impl LateLintPass for UnconditionalRecursion {
         fn expr_refers_to_this_method(tcx: &ty::ctxt,
                                       method: &ty::Method,
                                       id: ast::NodeId) -> bool {
-            let tables = tcx.tables.borrow();
-
             // Check for method calls and overloaded operators.
-            if let Some(m) = tables.method_map.get(&ty::MethodCall::expr(id)) {
+            let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
+            if let Some(m) = opt_m {
                 if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
                     return true;
                 }
             }
 
             // Check for overloaded autoderef method calls.
-            if let Some(&adjustment::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) {
+            let opt_adj = tcx.tables.borrow().adjustments.get(&id).cloned();
+            if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
                 for i in 0..adj.autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, i as u32);
-                    if let Some(m) = tables.method_map.get(&method_call) {
+                    if let Some(m) = tcx.tables.borrow().method_map
+                                                        .get(&method_call)
+                                                        .cloned() {
                         if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
                             return true;
                         }
@@ -914,9 +929,13 @@ impl LateLintPass for UnconditionalRecursion {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
                     match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
                         Some(def::DefMethod(def_id)) => {
-                            let no_substs = &ty::ItemSubsts::empty();
-                            let ts = tables.item_substs.get(&callee.id).unwrap_or(no_substs);
-                            method_call_refers_to_method(tcx, method, def_id, &ts.substs, id)
+                            let item_substs =
+                                tcx.tables.borrow().item_substs
+                                                   .get(&callee.id)
+                                                   .cloned()
+                                                   .unwrap_or_else(|| ty::ItemSubsts::empty());
+                            method_call_refers_to_method(
+                                tcx, method, def_id, &item_substs.substs, id)
                         }
                         _ => false
                     }
@@ -953,7 +972,12 @@ impl LateLintPass for UnconditionalRecursion {
                         traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
                                                 trait_ref.to_poly_trait_predicate());
 
-                    let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node);
+                    // unwrap() is ok here b/c `method` is the method
+                    // defined in this crate whose body we are
+                    // checking, so it's always local
+                    let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
+
+                    let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
                     let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false);
                     let mut selcx = traits::SelectionContext::new(&infcx);
                     match selcx.select(&obligation) {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 920ecab7527..f3549e6dda7 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -139,8 +139,8 @@ impl LateLintPass for UnusedResults {
             ty::TyBool => return,
             ty::TyStruct(def, _) |
             ty::TyEnum(def, _) => {
-                if def.did.is_local() {
-                    if let hir_map::NodeItem(it) = cx.tcx.map.get(def.did.node) {
+                if let Some(def_node_id) = cx.tcx.map.as_local_node_id(def.did) {
+                    if let hir_map::NodeItem(it) = cx.tcx.map.get(def_node_id) {
                         check_must_use(cx, &it.attrs, s.span)
                     } else {
                         false
diff --git a/src/librustc_mir/dump.rs b/src/librustc_mir/dump.rs
index 9b3514028af..ebde7e1d097 100644
--- a/src/librustc_mir/dump.rs
+++ b/src/librustc_mir/dump.rs
@@ -26,7 +26,6 @@ use repr::Mir;
 use std::fs::File;
 use tcx::{PatNode, Cx};
 
-use self::rustc::middle::def_id::DefId;
 use self::rustc::middle::infer;
 use self::rustc::middle::region::CodeExtentData;
 use self::rustc::middle::ty::{self, Ty};
@@ -210,7 +209,7 @@ fn closure_self_ty<'a,'tcx>(tcx: &ty::ctxt<'tcx>,
     let region =
         tcx.mk_region(region);
 
-    match tcx.closure_kind(DefId::local(closure_expr_id)) {
+    match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
         ty::ClosureKind::FnClosureKind =>
             tcx.mk_ref(region,
                        ty::TypeAndMut { ty: closure_ty,
diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs
index 6c9713b003b..97becd474b1 100644
--- a/src/librustc_mir/tcx/expr.rs
+++ b/src/librustc_mir/tcx/expr.rs
@@ -17,7 +17,6 @@ use tcx::block;
 use tcx::pattern::PatNode;
 use tcx::rustc::front::map;
 use tcx::rustc::middle::def;
-use tcx::rustc::middle::def_id::DefId;
 use tcx::rustc::middle::region::CodeExtent;
 use tcx::rustc::middle::pat_util;
 use tcx::rustc::middle::ty::{self, Ty};
@@ -570,13 +569,13 @@ fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
 
     match def {
-        def::DefLocal(node_id) => {
+        def::DefLocal(_, node_id) => {
             ExprKind::VarRef {
                 id: node_id,
             }
         }
 
-        def::DefUpvar(id_var, index, closure_expr_id) => {
+        def::DefUpvar(_, id_var, index, closure_expr_id) => {
             debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
             let var_ty = cx.tcx.node_id_to_type(id_var);
 
@@ -612,7 +611,7 @@ fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
             let region =
                 cx.tcx.mk_region(region);
 
-            let self_expr = match cx.tcx.closure_kind(DefId::local(closure_expr_id)) {
+            let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
                 ty::ClosureKind::FnClosureKind => {
                     let ref_closure_ty =
                         cx.tcx.mk_ref(region,
@@ -818,7 +817,7 @@ fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
                                freevar: &ty::Freevar,
                                freevar_ty: Ty<'tcx>)
                                -> ExprRef<Cx<'a,'tcx>> {
-    let id_var = freevar.def.def_id().node;
+    let id_var = freevar.def.var_id();
     let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id };
     let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
     let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 2090527ca20..ca5411f9c79 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -263,19 +263,26 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     hir::TyPath(..) => {
                         match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
                             def::DefPrimTy(..) => true,
+                            def::DefSelfTy(..) => true,
                             def => {
                                 let did = def.def_id();
-                                !did.is_local() ||
-                                 self.exported_items.contains(&did.node)
+                                if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+                                    self.exported_items.contains(&node_id)
+                                } else {
+                                    true
+                                }
                             }
                         }
                     }
                     _ => true,
                 };
-                let tr = self.tcx.impl_trait_ref(DefId::local(item.id));
+                let tr = self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id));
                 let public_trait = tr.clone().map_or(false, |tr| {
-                    !tr.def_id.is_local() ||
-                     self.exported_items.contains(&tr.def_id.node)
+                    if let Some(node_id) = self.tcx.map.as_local_node_id(tr.def_id) {
+                        self.exported_items.contains(&node_id)
+                    } else {
+                        true
+                    }
                 });
 
                 if public_ty || public_trait {
@@ -331,11 +338,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             hir::ItemTy(ref ty, _) if public_first => {
                 if let hir::TyPath(..) = ty.node {
                     match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
-                        def::DefPrimTy(..) | def::DefTyParam(..) => {},
+                        def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
                         def => {
                             let did = def.def_id();
-                            if did.is_local() {
-                                self.exported_items.insert(did.node);
+                            if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+                                self.exported_items.insert(node_id);
                             }
                         }
                     }
@@ -363,8 +370,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
         if self.prev_exported {
             assert!(self.export_map.contains_key(&id), "wut {}", id);
             for export in self.export_map.get(&id).unwrap() {
-                if export.def_id.is_local() {
-                    self.reexports.insert(export.def_id.node);
+                if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
+                    self.reexports.insert(node_id);
                 }
             }
         }
@@ -404,7 +411,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
     // Determines whether the given definition is public from the point of view
     // of the current item.
     fn def_privacy(&self, did: DefId) -> PrivacyResult {
-        if !did.is_local() {
+        let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+            node_id
+        } else {
             if self.external_exports.contains(&did) {
                 debug!("privacy - {:?} was externally exported", did);
                 return Allowable;
@@ -496,19 +505,19 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
                     ExternallyDenied
                 }
             };
-        }
+        };
 
         debug!("privacy - local {} not public all the way down",
-               self.tcx.map.node_to_string(did.node));
+               self.tcx.map.node_to_string(node_id));
         // return quickly for things in the same module
-        if self.parents.get(&did.node) == self.parents.get(&self.curitem) {
+        if self.parents.get(&node_id) == self.parents.get(&self.curitem) {
             debug!("privacy - same parent, we're done here");
             return Allowable;
         }
 
         // We now know that there is at least one private member between the
         // destination and the root.
-        let mut closest_private_id = did.node;
+        let mut closest_private_id = node_id;
         loop {
             debug!("privacy - examining {}", self.nodestr(closest_private_id));
             let vis = match self.tcx.map.find(closest_private_id) {
@@ -578,6 +587,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
         }
     }
 
+    /// True if `id` is both local and private-accessible
+    fn local_private_accessible(&self, did: DefId) -> bool {
+        if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+            self.private_accessible(node_id)
+        } else {
+            false
+        }
+    }
+
     /// For a local private node in the AST, this function will determine
     /// whether the node is accessible by the current module that iteration is
     /// inside.
@@ -639,11 +657,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             DisallowedBy(id) => id,
         };
 
-        // If we're disallowed by a particular id, then we attempt to give a
-        // nice error message to say why it was disallowed. It was either
-        // because the item itself is private or because its parent is private
-        // and its parent isn't in our ancestry.
-        let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+        // If we're disallowed by a particular id, then we attempt to
+        // give a nice error message to say why it was disallowed. It
+        // was either because the item itself is private or because
+        // its parent is private and its parent isn't in our
+        // ancestry. (Both the item being checked and its parent must
+        // be local.)
+        let def_id = source_did.unwrap_or(to_check);
+        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
+        let (err_span, err_msg) = if id == node_id {
             return Some((span, format!("{} is private", msg), None));
         } else {
             (span, format!("{} is inaccessible", msg))
@@ -663,8 +685,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
                         };
                         let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
                         let did = def.def_id();
-                        assert!(did.is_local());
-                        match self.tcx.map.get(did.node) {
+                        let node_id = self.tcx.map.as_local_node_id(did).unwrap();
+                        match self.tcx.map.get(node_id) {
                             ast_map::NodeItem(item) => item,
                             _ => self.tcx.sess.span_bug(item.span,
                                                         "path is not an item")
@@ -699,9 +721,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             }
             UnnamedField(idx) => &v.fields[idx]
         };
-        if field.vis == hir::Public ||
-            (field.did.is_local() && self.private_accessible(field.did.node)) {
-            return
+        if field.vis == hir::Public || self.local_private_accessible(field.did) {
+            return;
         }
 
         let struct_desc = match def.adt_kind() {
@@ -891,11 +912,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                         _ => expr_ty
                     }.ty_adt_def().unwrap();
                     let any_priv = def.struct_variant().fields.iter().any(|f| {
-                        f.vis != hir::Public && (
-                            !f.did.is_local() ||
-                                    !self.private_accessible(f.did.node))
-                        });
-
+                        f.vis != hir::Public && !self.local_private_accessible(f.did)
+                    });
                     if any_priv {
                         span_err!(self.tcx.sess, expr.span, E0450,
                                   "cannot invoke tuple struct constructor with private \
@@ -1131,21 +1149,22 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
         let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
             // `int` etc. (None doesn't seem to occur.)
-            None | Some(def::DefPrimTy(..)) => return false,
+            None | Some(def::DefPrimTy(..)) | Some(def::DefSelfTy(..)) => return false,
             Some(def) => def.def_id(),
         };
+
         // A path can only be private if:
         // it's in this crate...
-        if !did.is_local() {
+        if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+            // .. and it corresponds to a private type in the AST (this returns
+            // None for type parameters)
+            match self.tcx.map.find(node_id) {
+                Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
+                Some(_) | None => false,
+            }
+        } else {
             return false
         }
-
-        // .. and it corresponds to a private type in the AST (this returns
-        // None for type parameters)
-        match self.tcx.map.find(did.node) {
-            Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
-            Some(_) | None => false,
-        }
     }
 
     fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
@@ -1245,7 +1264,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                                               |tr| {
                         let did = self.tcx.trait_ref_to_def_id(tr);
 
-                        !did.is_local() || self.trait_is_public(did.node)
+                        if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+                            self.trait_is_public(node_id)
+                        } else {
+                            true // external traits must be public
+                        }
                     });
 
                 // `true` iff this is a trait impl or at least one method is public.
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 8a15eabd614..f74144565fc 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -34,7 +34,7 @@ use self::NamespaceError::*;
 use rustc::metadata::csearch;
 use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
 use rustc::middle::def::*;
-use rustc::middle::def_id::DefId;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
 
 use syntax::ast::{Name, NodeId};
 use syntax::attr::AttrMetaMethods;
@@ -387,7 +387,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
             ItemExternCrate(_) => {
                 // n.b. we don't need to look at the path option here, because cstore already did
                 if let Some(crate_id) = self.session.cstore.find_extern_mod_stmt_cnum(item.id) {
-                    let def_id = DefId { krate: crate_id, node: 0 };
+                    let def_id = DefId { krate: crate_id, index: CRATE_DEF_INDEX };
                     self.external_exports.insert(def_id);
                     let parent_link = ModuleParentLink(Rc::downgrade(parent), name);
                     let external_module = Rc::new(Module::new(parent_link,
@@ -409,7 +409,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let name_bindings = self.add_child(name, parent, ForbidDuplicateModules, sp);
 
                 let parent_link = self.get_parent_link(parent, name);
-                let def_id = DefId { krate: 0, node: item.id };
+                let def_id = self.ast_map.local_def_id(item.id);
                 name_bindings.define_module(parent_link,
                                             Some(def_id),
                                             NormalModuleKind,
@@ -427,18 +427,20 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
                 let mutbl = m == hir::MutMutable;
 
-                name_bindings.define_value(DefStatic(DefId::local(item.id), mutbl), sp, modifiers);
+                name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
+                                           sp,
+                                           modifiers);
                 parent.clone()
             }
             ItemConst(_, _) => {
                 self.add_child(name, parent, ForbidDuplicateValues, sp)
-                    .define_value(DefConst(DefId::local(item.id)), sp, modifiers);
+                    .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
                 parent.clone()
             }
             ItemFn(_, _, _, _, _, _) => {
                 let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
 
-                let def = DefFn(DefId::local(item.id), false);
+                let def = DefFn(self.ast_map.local_def_id(item.id), false);
                 name_bindings.define_value(def, sp, modifiers);
                 parent.clone()
             }
@@ -448,12 +450,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let name_bindings =
                     self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp);
 
-                name_bindings.define_type(DefTy(DefId::local(item.id), false), sp,
+                name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false), sp,
                                           modifiers);
 
                 let parent_link = self.get_parent_link(parent, name);
                 name_bindings.set_module_kind(parent_link,
-                                              Some(DefId::local(item.id)),
+                                              Some(self.ast_map.local_def_id(item.id)),
                                               TypeModuleKind,
                                               false,
                                               is_public,
@@ -465,11 +467,13 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let name_bindings =
                     self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp);
 
-                name_bindings.define_type(DefTy(DefId::local(item.id), true), sp, modifiers);
+                name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), true),
+                                          sp,
+                                          modifiers);
 
                 let parent_link = self.get_parent_link(parent, name);
                 name_bindings.set_module_kind(parent_link,
-                                              Some(DefId::local(item.id)),
+                                              Some(self.ast_map.local_def_id(item.id)),
                                               EnumModuleKind,
                                               false,
                                               is_public,
@@ -478,9 +482,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let module = name_bindings.get_module();
 
                 for variant in &(*enum_definition).variants {
+                    let item_def_id = self.ast_map.local_def_id(item.id);
                     self.build_reduced_graph_for_variant(
                         &**variant,
-                        DefId::local(item.id),
+                        item_def_id,
                         &module);
                 }
                 parent.clone()
@@ -497,12 +502,16 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 let name_bindings = self.add_child(name, parent, forbid, sp);
 
                 // Define a name in the type namespace.
-                name_bindings.define_type(DefTy(DefId::local(item.id), false), sp, modifiers);
+                name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false),
+                                          sp,
+                                          modifiers);
 
                 // If this is a newtype or unit-like struct, define a name
                 // in the value namespace as well
                 if let Some(cid) = ctor_id {
-                    name_bindings.define_value(DefStruct(DefId::local(cid)), sp, modifiers);
+                    name_bindings.define_value(DefStruct(self.ast_map.local_def_id(cid)),
+                                               sp,
+                                               modifiers);
                 }
 
                 // Record the def ID and fields of this struct.
@@ -512,7 +521,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                         UnnamedField(_) => None
                     }
                 }).collect();
-                self.structs.insert(DefId::local(item.id), named_fields);
+                let item_def_id = self.ast_map.local_def_id(item.id);
+                self.structs.insert(item_def_id, named_fields);
 
                 parent.clone()
             }
@@ -527,14 +537,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                 // Add all the items within to a new module.
                 let parent_link = self.get_parent_link(parent, name);
                 name_bindings.define_module(parent_link,
-                                            Some(DefId::local(item.id)),
+                                            Some(self.ast_map.local_def_id(item.id)),
                                             TraitModuleKind,
                                             false,
                                             is_public,
                                             sp);
                 let module_parent = name_bindings.get_module();
 
-                let def_id = DefId::local(item.id);
+                let def_id = self.ast_map.local_def_id(item.id);
 
                 // Add the names of all the items to the trait info.
                 for trait_item in items {
@@ -545,25 +555,25 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
 
                     match trait_item.node {
                         hir::ConstTraitItem(..) => {
-                            let def = DefAssociatedConst(DefId::local(trait_item.id));
+                            let def = DefAssociatedConst(self.ast_map.local_def_id(trait_item.id));
                             // NB: not DefModifiers::IMPORTABLE
                             name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
                         }
                         hir::MethodTraitItem(..) => {
-                            let def = DefMethod(DefId::local(trait_item.id));
+                            let def = DefMethod(self.ast_map.local_def_id(trait_item.id));
                             // NB: not DefModifiers::IMPORTABLE
                             name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
                         }
                         hir::TypeTraitItem(..) => {
-                            let def = DefAssociatedTy(DefId::local(item.id),
-                                                      DefId::local(trait_item.id));
+                            let def = DefAssociatedTy(self.ast_map.local_def_id(item.id),
+                                                      self.ast_map.local_def_id(trait_item.id));
                             // NB: not DefModifiers::IMPORTABLE
                             name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
                         }
                     }
 
-                    self.trait_item_map.insert((trait_item.name, def_id),
-                                               DefId::local(trait_item.id));
+                    let trait_item_def_id = self.ast_map.local_def_id(trait_item.id);
+                    self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id);
                 }
 
                 name_bindings.define_type(DefTrait(def_id), sp, modifiers);
@@ -583,7 +593,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
             TupleVariantKind(_) => false,
             StructVariantKind(_) => {
                 // Not adding fields for variants as they are not accessed with a self receiver
-                self.structs.insert(DefId::local(variant.node.id), Vec::new());
+                let variant_def_id = self.ast_map.local_def_id(variant.node.id);
+                self.structs.insert(variant_def_id, Vec::new());
                 true
             }
         };
@@ -594,10 +605,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
         // variants are always treated as importable to allow them to be glob
         // used
         child.define_value(DefVariant(item_id,
-                                      DefId::local(variant.node.id), is_exported),
+                                      self.ast_map.local_def_id(variant.node.id), is_exported),
                            variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
         child.define_type(DefVariant(item_id,
-                                     DefId::local(variant.node.id), is_exported),
+                                     self.ast_map.local_def_id(variant.node.id), is_exported),
                           variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
     }
 
@@ -618,10 +629,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
 
         let def = match foreign_item.node {
             ForeignItemFn(..) => {
-                DefFn(DefId::local(foreign_item.id), false)
+                DefFn(self.ast_map.local_def_id(foreign_item.id), false)
             }
             ForeignItemStatic(_, m) => {
-                DefStatic(DefId::local(foreign_item.id), m)
+                DefStatic(self.ast_map.local_def_id(foreign_item.id), m)
             }
         };
         name_bindings.define_value(def, foreign_item.span, modifiers);
@@ -805,7 +816,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
             self.structs.insert(def_id, fields);
           }
           DefLocal(..) | DefPrimTy(..) | DefTyParam(..) |
-          DefUse(..) | DefUpvar(..) | DefRegion(..) |
+          DefUse(..) | DefUpvar(..) |
           DefLabel(..) | DefSelfTy(..) => {
             panic!("didn't expect `{:?}`", def);
           }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4f6b3f9353a..40477d8698e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -65,7 +65,7 @@ use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
 use rustc::util::lev_distance::lev_distance;
 
 use syntax::ast;
-use syntax::ast::{Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
+use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
 use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32};
 use syntax::attr::AttrMetaMethods;
 use syntax::ext::mtwt;
@@ -1188,8 +1188,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
            make_glob_map: MakeGlobMap) -> Resolver<'a, 'tcx> {
         let graph_root = NameBindings::new();
 
+        let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
         graph_root.define_module(NoParentLink,
-                                 Some(DefId { krate: 0, node: 0 }),
+                                 Some(root_def_id),
                                  NormalModuleKind,
                                  false,
                                  true,
@@ -1257,8 +1258,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     fn get_trait_name(&self, did: DefId) -> Name {
-        if did.is_local() {
-            self.ast_map.expect_item(did.node).name
+        if let Some(node_id) = self.ast_map.as_local_node_id(did) {
+            self.ast_map.expect_item(node_id).name
         } else {
             csearch::get_trait_name(&self.session.cstore, did)
         }
@@ -1981,7 +1982,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 self.session.span_bug(span,
                     &format!("unexpected {:?} in bindings", def))
             }
-            DefLocal(node_id) => {
+            DefLocal(_, node_id) => {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind => {
@@ -1989,11 +1990,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         }
                         ClosureRibKind(function_id) => {
                             let prev_def = def;
+                            let node_def_id = self.ast_map.local_def_id(node_id);
 
                             let mut seen = self.freevars_seen.borrow_mut();
                             let seen = seen.entry(function_id).or_insert_with(|| NodeMap());
                             if let Some(&index) = seen.get(&node_id) {
-                                def = DefUpvar(node_id, index, function_id);
+                                def = DefUpvar(node_def_id, node_id, index, function_id);
                                 continue;
                             }
                             let mut freevars = self.freevars.borrow_mut();
@@ -2002,7 +2004,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             let depth = vec.len();
                             vec.push(Freevar { def: prev_def, span: span });
 
-                            def = DefUpvar(node_id, depth, function_id);
+                            def = DefUpvar(node_def_id, node_id, depth, function_id);
                             seen.insert(node_id, depth);
                         }
                         ItemRibKind | MethodRibKind => {
@@ -2156,7 +2158,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                                TypeSpace,
                                                                ItemRibKind),
                                              |this| {
-                    this.with_self_rib(DefSelfTy(Some(DefId::local(item.id)), None), |this| {
+                    let local_def_id = this.ast_map.local_def_id(item.id);
+                    this.with_self_rib(DefSelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_ty_param_bound, bounds);
 
@@ -2280,7 +2283,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     function_type_rib.bindings.insert(name,
                         DlDef(DefTyParam(space,
                                          index as u32,
-                                         DefId::local(type_parameter.id),
+                                         self.ast_map.local_def_id(type_parameter.id),
                                          name)));
                 }
                 self.type_ribs.push(function_type_rib);
@@ -2815,7 +2818,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             debug!("(resolving pattern) binding `{}`",
                                    renamed);
 
-                            let def = DefLocal(pattern.id);
+                            let def_id = self.ast_map.local_def_id(pattern.id);
+                            let def = DefLocal(def_id, pattern.id);
 
                             // Record the definition so that later passes
                             // will be able to distinguish variants from
@@ -3497,8 +3501,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         fn is_static_method(this: &Resolver, did: DefId) -> bool {
-            if did.is_local() {
-                let sig = match this.ast_map.get(did.node) {
+            if let Some(node_id) = this.ast_map.as_local_node_id(did) {
+                let sig = match this.ast_map.get(node_id) {
                     hir_map::NodeTraitItem(trait_item) => match trait_item.node {
                         hir::MethodTraitItem(ref sig, _) => sig,
                         _ => return false
@@ -3845,9 +3849,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         fn add_trait_info(found_traits: &mut Vec<DefId>,
                           trait_def_id: DefId,
                           name: Name) {
-            debug!("(adding trait info) found trait {}:{} for method '{}'",
-                trait_def_id.krate,
-                trait_def_id.node,
+            debug!("(adding trait info) found trait {:?} for method '{}'",
+                trait_def_id,
                 name);
             found_traits.push(trait_def_id);
         }
diff --git a/src/librustc_resolve/record_exports.rs b/src/librustc_resolve/record_exports.rs
index 36ed2c14579..0eb1e2cc06f 100644
--- a/src/librustc_resolve/record_exports.rs
+++ b/src/librustc_resolve/record_exports.rs
@@ -102,9 +102,9 @@ impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> {
         self.add_exports_for_module(&mut exports, module_);
         match module_.def_id.get() {
             Some(def_id) => {
-                self.export_map.insert(def_id.node, exports);
-                debug!("(computing exports) writing exports for {} (some)",
-                       def_id.node);
+                let node_id = self.ast_map.as_local_node_id(def_id).unwrap();
+                self.export_map.insert(node_id, exports);
+                debug!("(computing exports) writing exports for {} (some)", node_id);
             }
             None => {}
         }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 3a98df0bdfd..6cbee926a08 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -25,7 +25,7 @@ use metadata::loader::METADATA_FILENAME;
 use metadata::{encoder, cstore, filesearch, csearch, creader};
 use middle::dependency_format::Linkage;
 use middle::ty::{self, Ty};
-use rustc::front::map::{PathElem, PathElems, PathName};
+use rustc::front::map::DefPath;
 use trans::{CrateContext, CrateTranslation, gensym_name};
 use util::common::time;
 use util::sha2::{Digest, Sha256};
@@ -36,6 +36,7 @@ use std::env;
 use std::ffi::OsString;
 use std::fs::{self, PathExt};
 use std::io::{self, Read, Write};
+use std::iter::once;
 use std::mem;
 use std::path::{Path, PathBuf};
 use std::process::Command;
@@ -44,7 +45,7 @@ use flate;
 use serialize::hex::ToHex;
 use syntax::ast;
 use syntax::codemap::Span;
-use syntax::parse::token;
+use syntax::parse::token::{self, InternedString};
 use syntax::attr::AttrMetaMethods;
 
 use rustc_front::hir;
@@ -284,8 +285,7 @@ pub fn sanitize(s: &str) -> String {
     return result;
 }
 
-pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
-                                           hash: Option<&str>) -> String {
+pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
     // Follow C++ namespace-mangling style, see
     // http://en.wikipedia.org/wiki/Name_mangling for more info.
     //
@@ -308,8 +308,8 @@ pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
     }
 
     // First, connect each component with <len, name> pairs.
-    for e in path {
-        push(&mut n, &e.name().as_str())
+    for data in path {
+        push(&mut n, &data);
     }
 
     match hash {
@@ -321,11 +321,13 @@ pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
     n
 }
 
-pub fn exported_name(path: PathElems, hash: &str) -> String {
+pub fn exported_name(path: DefPath, hash: &str) -> String {
+    let path = path.into_iter()
+                   .map(|e| e.data.as_interned_str());
     mangle(path, Some(hash))
 }
 
-pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathElems,
+pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: DefPath,
                                       t: Ty<'tcx>, id: ast::NodeId) -> String {
     let mut hash = get_symbol_hash(ccx, t);
 
@@ -353,14 +355,17 @@ pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathEl
 pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                       t: Ty<'tcx>,
                                                       name: &str) -> String {
-    let path = [PathName(token::intern(&t.to_string())),
-                gensym_name(name)];
+    let path = [token::intern(&t.to_string()).as_str(), gensym_name(name).as_str()];
     let hash = get_symbol_hash(ccx, t);
     mangle(path.iter().cloned(), Some(&hash[..]))
 }
 
-pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> String {
-    mangle(path.chain(Some(gensym_name(flav))), None)
+pub fn mangle_internal_name_by_path_and_seq(path: DefPath, flav: &str) -> String {
+    let names =
+        path.into_iter()
+            .map(|e| e.data.as_interned_str())
+            .chain(once(gensym_name(flav).as_str())); // append unique version of "flav"
+    mangle(names, None)
 }
 
 pub fn get_linker(sess: &Session) -> (String, Command) {
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 6c53762c3ea..dc0bdd8573d 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -235,7 +235,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
         }
         let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
         match def {
-            def::DefPrimTy(_) => None,
+            def::DefPrimTy(..) => None,
+            def::DefSelfTy(..) => None,
             _ => Some(def.def_id()),
         }
     }
@@ -257,14 +258,13 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             def::DefStatic(_, _) |
             def::DefConst(_) |
             def::DefAssociatedConst(..) |
-            def::DefLocal(_) |
+            def::DefLocal(..) |
             def::DefVariant(_, _, _) |
             def::DefUpvar(..) => Some(recorder::VarRef),
 
             def::DefFn(..) => Some(recorder::FnRef),
 
             def::DefSelfTy(..) |
-            def::DefRegion(_) |
             def::DefLabel(_) |
             def::DefTyParam(..) |
             def::DefUse(_) |
@@ -721,7 +721,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                     }
                 }
             }
-            def::DefLocal(_) |
+            def::DefLocal(..) |
             def::DefStatic(_,_) |
             def::DefConst(..) |
             def::DefAssociatedConst(..) |
@@ -1170,7 +1170,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
             }
             let def = def_map.get(&id).unwrap().full_def();
             match def {
-                def::DefLocal(id) => {
+                def::DefLocal(_, id) => {
                     let value = if immut == ast::MutImmutable {
                         self.span.snippet(p.span).to_string()
                     } else {
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index afd16bea6d7..00781bd2711 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -10,7 +10,7 @@
 
 use middle::ty;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 
 use std::env;
 use std::fs::{self, File};
@@ -348,15 +348,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> FunctionData {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let qualname = match self.tcx.impl_of_method(DefId::local(id)) {
-            Some(impl_id) => match self.tcx.map.get(impl_id.node) {
-                NodeItem(item) => {
+        let qualname = 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)) => {
                     match item.node {
                         hir::ItemImpl(_, _, _, _, ref ty, _) => {
                             let mut result = String::from("<");
                             result.push_str(&rustc_front::print::pprust::ty_to_string(&**ty));
 
-                            match self.tcx.trait_of_item(DefId::local(id)) {
+                            match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
                                 Some(def_id) => {
                                     result.push_str(" as ");
                                     result.push_str(
@@ -369,27 +369,27 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         }
                         _ => {
                             self.tcx.sess.span_bug(span,
-                                &format!("Container {} for method {} not an impl?",
-                                         impl_id.node, id));
+                                &format!("Container {:?} for method {} not an impl?",
+                                         impl_id, id));
                         }
                     }
                 }
-                _ => {
+                r => {
                     self.tcx.sess.span_bug(span,
-                        &format!("Container {} for method {} is not a node item {:?}",
-                                 impl_id.node, id, self.tcx.map.get(impl_id.node)));
-                }
+                        &format!("Container {:?} for method {} is not a node item {:?}",
+                                 impl_id, id, r));
+                },
             },
-            None => match self.tcx.trait_of_item(DefId::local(id)) {
+            None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
                 Some(def_id) => {
-                    match self.tcx.map.get(def_id.node) {
-                        NodeItem(_) => {
+                    match self.tcx.map.get_if_local(def_id) {
+                        Some(NodeItem(_)) => {
                             format!("::{}", self.tcx.item_path_str(def_id))
                         }
-                        _ => {
+                        r => {
                             self.tcx.sess.span_bug(span,
-                                &format!("Could not find container {} for method {}",
-                                         def_id.node, id));
+                                &format!("Could not find container {:?} for method {}, got {:?}",
+                                         def_id, id, r));
                         }
                     }
                 }
@@ -402,11 +402,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
         let qualname = format!("{}::{}", qualname, name);
 
-        let decl_id = self.tcx.trait_item_of_item(DefId::local(id))
+        let def_id = self.tcx.map.local_def_id(id);
+        let decl_id =
+            self.tcx.trait_item_of_item(def_id)
             .and_then(|new_id| {
-                let def_id = new_id.def_id();
-                if def_id.node != 0 && def_id != DefId::local(id) {
-                    Some(def_id)
+                let new_def_id = new_id.def_id();
+                if new_def_id != def_id {
+                    Some(new_def_id)
                 } else {
                     None
                 }
@@ -595,13 +597,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
         let def_id = mr.def_id();
-        if def_id.krate != LOCAL_CRATE {
-            return false;
-        }
-
-        let trait_item = self.tcx.map.expect_trait_item(def_id.node);
-        if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
-            true
+        if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+            let trait_item = self.tcx.map.expect_trait_item(node_id);
+            if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
+                true
+            } else {
+                false
+            }
         } else {
             false
         }
@@ -635,7 +637,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
         let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
         match def {
-            def::DefPrimTy(_) => None,
+            def::DefPrimTy(_) | def::DefSelfTy(..) => None,
             _ => Some(def.def_id()),
         }
     }
diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs
index f8e68649853..f388f76c744 100644
--- a/src/librustc_trans/save/recorder.rs
+++ b/src/librustc_trans/save/recorder.rs
@@ -13,7 +13,8 @@ pub use self::Row::*;
 use super::escape;
 use super::span_utils::SpanUtils;
 
-use middle::def_id::DefId;
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
 
 use std::io::Write;
 
@@ -21,7 +22,7 @@ use syntax::ast;
 use syntax::ast::NodeId;
 use syntax::codemap::*;
 
-const ZERO_DEF_ID: DefId = DefId { node: 0, krate: 0 };
+const CRATE_ROOT_DEF_ID: DefId = DefId { krate: LOCAL_CRATE, index: CRATE_DEF_INDEX };
 
 pub struct Recorder {
     // output file
@@ -381,7 +382,7 @@ impl<'a> FmtStrs<'a> {
                       decl_id: Option<DefId>,
                       scope_id: NodeId) {
         let values = match decl_id {
-            Some(decl_id) => svec!(id, name, decl_id.node, decl_id.krate, scope_id),
+            Some(decl_id) => svec!(id, name, decl_id.index.as_usize(), decl_id.krate, scope_id),
             None => svec!(id, name, "", "", scope_id),
         };
         self.check_and_record(Function,
@@ -436,15 +437,15 @@ impl<'a> FmtStrs<'a> {
                     ref_id: Option<DefId>,
                     trait_id: Option<DefId>,
                     scope_id: NodeId) {
-        let ref_id = ref_id.unwrap_or(ZERO_DEF_ID);
-        let trait_id = trait_id.unwrap_or(ZERO_DEF_ID);
+        let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID);
+        let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID);
         self.check_and_record(Impl,
                               span,
                               sub_span,
                               svec!(id,
-                                    ref_id.node,
+                                    ref_id.index.as_usize(),
                                     ref_id.krate,
-                                    trait_id.node,
+                                    trait_id.index.as_usize(),
                                     trait_id.krate,
                                     scope_id));
     }
@@ -469,14 +470,11 @@ impl<'a> FmtStrs<'a> {
                          mod_id: Option<DefId>,
                          name: &str,
                          parent: NodeId) {
-        let (mod_node, mod_crate) = match mod_id {
-            Some(mod_id) => (mod_id.node, mod_id.krate),
-            None => (0, 0),
-        };
+        let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID);
         self.check_and_record(UseAlias,
                               span,
                               sub_span,
-                              svec!(id, mod_node, mod_crate, name, parent));
+                              svec!(id, mod_id.index.as_usize(), mod_id.krate, name, parent));
     }
 
     pub fn use_glob_str(&mut self,
@@ -513,7 +511,7 @@ impl<'a> FmtStrs<'a> {
         self.check_and_record(Inheritance,
                               span,
                               sub_span,
-                              svec!(base_id.node,
+                              svec!(base_id.index.as_usize(),
                                     base_id.krate,
                                     deriv_id,
                                     0));
@@ -527,7 +525,7 @@ impl<'a> FmtStrs<'a> {
         self.check_and_record(FnCall,
                               span,
                               sub_span,
-                              svec!(id.node, id.krate, "", scope_id));
+                              svec!(id.index.as_usize(), id.krate, "", scope_id));
     }
 
     pub fn meth_call_str(&mut self,
@@ -536,18 +534,15 @@ impl<'a> FmtStrs<'a> {
                          defid: Option<DefId>,
                          declid: Option<DefId>,
                          scope_id: NodeId) {
-        let (dfn, dfk) = match defid {
-            Some(defid) => (defid.node, defid.krate),
-            None => (0, 0),
-        };
+        let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID);
         let (dcn, dck) = match declid {
-            Some(declid) => (s!(declid.node), s!(declid.krate)),
+            Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)),
             None => ("".to_string(), "".to_string()),
         };
         self.check_and_record(MethodCall,
                               span,
                               sub_span,
-                              svec!(dfn, dfk, dcn, dck, scope_id));
+                              svec!(defid.index.as_usize(), defid.krate, dcn, dck, scope_id));
     }
 
     pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) {
@@ -600,6 +595,6 @@ impl<'a> FmtStrs<'a> {
         self.check_and_record(kind,
                               span,
                               sub_span,
-                              svec!(id.node, id.krate, "", scope_id));
+                              svec!(id.index.as_usize(), id.krate, "", scope_id));
     }
 }
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index 67bfe58089e..1eb4a7a5e0c 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -1432,19 +1432,19 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
     let (vid, field) = match discr.node {
         hir::ExprPath(..) => match bcx.def(discr.id) {
-            def::DefLocal(vid) | def::DefUpvar(vid, _, _) => (vid, None),
+            def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None),
             _ => return false
         },
         hir::ExprField(ref base, field) => {
             let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
-                Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid,
+                Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
                 _ => return false
             };
             (vid, Some(mc::NamedField(field.node)))
         },
         hir::ExprTupField(ref base, field) => {
             let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
-                Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid,
+                Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
                 _ => return false
             };
             (vid, Some(mc::PositionalField(field.node)))
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 528b8f9e532..05b20ac3fb7 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -37,7 +37,7 @@ use llvm;
 use metadata::{csearch, encoder, loader};
 use middle::astencode;
 use middle::cfg;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::weak_lang_items;
 use middle::pat_util::simple_name;
@@ -1286,7 +1286,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
 
     // Create the drop-flag hints for every unfragmented path in the function.
     let tcx = fcx.ccx.tcx();
-    let fn_did = DefId { krate: LOCAL_CRATE, node: fcx.id };
+    let fn_did = tcx.map.local_def_id(fcx.id);
     let mut hints = fcx.lldropflag_hints.borrow_mut();
     let fragment_infos = tcx.fragment_infos.borrow();
 
@@ -1576,7 +1576,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            param_substs);
 
     let has_env = match closure_env {
-        closure::ClosureEnv::Closure(_) => true,
+        closure::ClosureEnv::Closure(..) => true,
         closure::ClosureEnv::NotClosure => false,
     };
 
@@ -2085,7 +2085,8 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
                     // error in trans. This is used to write compile-fail tests
                     // that actually test that compilation succeeds without
                     // reporting an error.
-                    if ccx.tcx().has_attr(DefId::local(item.id), "rustc_error") {
+                    let item_def_id = ccx.tcx().map.local_def_id(item.id);
+                    if ccx.tcx().has_attr(item_def_id, "rustc_error") {
                         ccx.tcx().sess.span_fatal(item.span, "compilation successful");
                     }
                 }
@@ -2252,13 +2253,14 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
                     Ok(id) => id,
                     Err(s) => { ccx.sess().fatal(&s[..]); }
                 };
-                let start_fn = if start_def_id.is_local() {
-                    get_item_val(ccx, start_def_id.node)
-                } else {
-                    let start_fn_type = csearch::get_type(ccx.tcx(),
-                                                          start_def_id).ty;
-                    trans_external_path(ccx, start_def_id, start_fn_type)
-                };
+                let start_fn =
+                    if let Some(start_node_id) = ccx.tcx().map.as_local_node_id(start_def_id) {
+                        get_item_val(ccx, start_node_id)
+                    } else {
+                        let start_fn_type = csearch::get_type(ccx.tcx(),
+                                                              start_def_id).ty;
+                        trans_external_path(ccx, start_def_id, start_fn_type)
+                    };
 
                 let args = {
                     let opaque_rust_main = llvm::LLVMBuildPointerCast(bld,
@@ -2307,10 +2309,11 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId,
     match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) {
         // Use provided name
         Some(name) => name.to_string(),
-        _ => ccx.tcx().map.with_path(id, |path| {
+        _ => {
+            let path = ccx.tcx().map.def_path_from_id(id);
             if attr::contains_name(attrs, "no_mangle") {
                 // Don't mangle
-                path.last().unwrap().to_string()
+                path.last().unwrap().data.to_string()
             } else {
                 match weak_lang_items::link_name(attrs) {
                     Some(name) => name.to_string(),
@@ -2320,7 +2323,7 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId,
                     }
                 }
             }
-        })
+        }
     }
 }
 
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index cfa77d57bf6..b806f36b910 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -22,8 +22,9 @@ use arena::TypedArena;
 use back::link;
 use session;
 use llvm::{self, ValueRef, get_params};
+use metadata::cstore::LOCAL_CRATE;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::infer::normalize_associated_type;
 use middle::subst;
 use middle::subst::{Substs};
@@ -139,8 +140,10 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
         match def {
             def::DefFn(did, _) if {
                 let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
-                let maybe_ast_node = maybe_def_id.and_then(|def_id| bcx.tcx().map
-                                                                             .find(def_id.node));
+                let maybe_ast_node = maybe_def_id.and_then(|def_id| {
+                    let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
+                    bcx.tcx().map.find(node_id)
+                });
                 match maybe_ast_node {
                     Some(hir_map::NodeStructCtor(_)) => true,
                     _ => false
@@ -161,7 +164,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
                                                     ExprId(ref_expr.id),
                                                     bcx.fcx.param_substs);
                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty }
+                let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
+                Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
             }
             def::DefFn(did, _) => {
                 fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
@@ -211,8 +215,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
             }
             def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
             def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
-            def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) |
-            def::DefTyParam(..) | def::DefSelfTy(..) => {
+            def::DefUse(..) | def::DefLabel(..) | def::DefTyParam(..) |
+            def::DefSelfTy(..) => {
                 bcx.tcx().sess.span_bug(
                     ref_expr.span,
                     &format!("cannot translate def {:?} \
@@ -403,10 +407,13 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
     let def_id = inline::maybe_instantiate_inline(ccx, def_id);
 
     fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
-        if !def_id.is_local() { return false; }
+        let node_id = match tcx.map.as_local_node_id(def_id) {
+            Some(n) => n,
+            None => { return false; }
+        };
         let map_node = session::expect(
             &tcx.sess,
-            tcx.map.find(def_id.node),
+            tcx.map.find(node_id),
             || "local item should be in ast map".to_string());
 
         match map_node {
@@ -464,9 +471,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
 
     // Find the actual function pointer.
     let mut val = {
-        if def_id.is_local() {
+        if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
             // Internal reference.
-            get_item_val(ccx, def_id.node)
+            get_item_val(ccx, node_id)
         } else {
             // External reference.
             trans_external_path(ccx, def_id, fn_type)
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index dc9ea62e9d1..d3509c2f813 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -36,6 +36,7 @@ use rustc_front::hir;
 
 
 fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                        closure_def_id: DefId,
                                         arg_scope_id: ScopeId,
                                         freevars: &[ty::Freevar])
                                         -> Block<'blk, 'tcx>
@@ -43,10 +44,9 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("closure::load_closure_environment");
 
     // Special case for small by-value selfs.
-    let closure_id = DefId::local(bcx.fcx.id);
-    let self_type = self_type_for_closure(bcx.ccx(), closure_id,
-                                                  node_id_type(bcx, closure_id.node));
-    let kind = kind_for_closure(bcx.ccx(), closure_id);
+    let closure_ty = node_id_type(bcx, bcx.fcx.id);
+    let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty);
+    let kind = kind_for_closure(bcx.ccx(), closure_def_id);
     let llenv = if kind == ty::FnOnceClosureKind &&
             !arg_is_indirect(bcx.ccx(), self_type) {
         let datum = rvalue_scratch_datum(bcx,
@@ -69,8 +69,8 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     };
 
     for (i, freevar) in freevars.iter().enumerate() {
-        let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
-                                     closure_expr_id: closure_id.node };
+        let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
+                                     closure_expr_id: bcx.fcx.id };
         let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
         let mut upvar_ptr = StructGEP(bcx, llenv, i);
         let captured_by_ref = match upvar_capture {
@@ -80,21 +80,21 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 true
             }
         };
-        let def_id = freevar.def.def_id();
-        bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
+        let node_id = freevar.def.var_id();
+        bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
 
         if kind == ty::FnOnceClosureKind && !captured_by_ref {
             let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
             bcx.fcx.schedule_drop_mem(arg_scope_id,
                                       upvar_ptr,
-                                      node_id_type(bcx, def_id.node),
+                                      node_id_type(bcx, node_id),
                                       hint)
         }
 
         if let Some(env_pointer_alloca) = env_pointer_alloca {
             debuginfo::create_captured_var_metadata(
                 bcx,
-                def_id.node,
+                node_id,
                 env_pointer_alloca,
                 i,
                 captured_by_ref,
@@ -107,7 +107,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
 pub enum ClosureEnv<'a> {
     NotClosure,
-    Closure(&'a [ty::Freevar]),
+    Closure(DefId, &'a [ty::Freevar]),
 }
 
 impl<'a> ClosureEnv<'a> {
@@ -116,11 +116,11 @@ impl<'a> ClosureEnv<'a> {
     {
         match self {
             ClosureEnv::NotClosure => bcx,
-            ClosureEnv::Closure(freevars) => {
+            ClosureEnv::Closure(def_id, freevars) => {
                 if freevars.is_empty() {
                     bcx
                 } else {
-                    load_closure_environment(bcx, arg_scope, freevars)
+                    load_closure_environment(bcx, def_id, arg_scope, freevars)
                 }
             }
         }
@@ -147,9 +147,8 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         return llfn;
     }
 
-    let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
-        mangle_internal_name_by_path_and_seq(path, "closure")
-    });
+    let path = ccx.tcx().def_path(closure_id);
+    let symbol = mangle_internal_name_by_path_and_seq(path, "closure");
 
     let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs));
     let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);
@@ -176,9 +175,14 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
                                     decl: &hir::FnDecl,
                                     body: &hir::Block,
                                     id: ast::NodeId,
+                                    closure_def_id: DefId, // (*)
                                     closure_substs: &'tcx ty::ClosureSubsts<'tcx>)
                                     -> Option<Block<'a, 'tcx>>
 {
+    // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
+    // defid of the closure in its original crate, whereas `id` will be the id of the local
+    // inlined copy.
+
     let param_substs = closure_substs.func_substs;
 
     let ccx = match dest {
@@ -188,10 +192,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     let tcx = ccx.tcx();
     let _icx = push_ctxt("closure::trans_closure_expr");
 
-    debug!("trans_closure_expr()");
+    debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
+           id, closure_def_id, closure_substs);
 
-    let closure_id = DefId::local(id);
-    let llfn = get_or_create_closure_declaration(ccx, closure_id, closure_substs);
+    let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
 
     // Get the type of this closure. Use the current `param_substs` as
     // the closure substitutions. This makes sense because the closure
@@ -200,7 +204,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     // of the closure expression.
 
     let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
-    let function_type = infcx.closure_type(closure_id, closure_substs);
+    let function_type = infcx.closure_type(closure_def_id, closure_substs);
 
     let freevars: Vec<ty::Freevar> =
         tcx.with_freevars(id, |fv| fv.iter().cloned().collect());
@@ -216,7 +220,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
                   &[],
                   sig.output,
                   function_type.abi,
-                  ClosureEnv::Closure(&freevars));
+                  ClosureEnv::Closure(closure_def_id, &freevars));
 
     // Don't hoist this to the top of the function. It's perfectly legitimate
     // to have a zero-size closure (in which case dest will be `Ignore`) and
@@ -235,7 +239,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     for (i, freevar) in freevars.iter().enumerate() {
         let datum = expr::trans_local_var(bcx, freevar.def);
         let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i);
-        let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
+        let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
                                      closure_expr_id: id };
         match tcx.upvar_capture(upvar_id).unwrap() {
             ty::UpvarCapture::ByValue => {
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 78f631371c0..d160465c619 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -39,7 +39,6 @@ use trans::type_of;
 use middle::traits;
 use middle::ty::{self, HasTypeFlags, Ty};
 use middle::ty::fold::{TypeFolder, TypeFoldable};
-use rustc::front::map::{PathElem, PathName};
 use rustc_front::hir;
 use util::nodemap::{FnvHashMap, NodeMap};
 
@@ -167,11 +166,11 @@ pub fn return_type_is_void(ccx: &CrateContext, ty: Ty) -> bool {
 
 /// Generates a unique symbol based off the name given. This is used to create
 /// unique symbols for things like closures.
-pub fn gensym_name(name: &str) -> PathElem {
+pub fn gensym_name(name: &str) -> ast::Name {
     let num = token::gensym(name).0;
     // use one colon which will get translated to a period by the mangler, and
     // we're guaranteed that `num` is globally unique for this crate.
-    PathName(token::gensym(&format!("{}:{}", name, num)))
+    token::gensym(&format!("{}:{}", name, num))
 }
 
 /*
@@ -1020,7 +1019,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                    trait_ref);
             ccx.sess().span_fatal(
                 span,
-                "reached the recursion limit during monomorphization");
+                "reached the recursion limit during monomorphization (selection ambiguity)");
         }
         Err(e) => {
             tcx.sess.span_bug(
@@ -1145,8 +1144,9 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }), ..}) => ty,
         _ => ctor_ty
     }.ty_adt_def().unwrap();
+    let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid);
     adt_def.variants.iter().find(|v| {
-        DefId::local(inlined_vid) == v.did ||
+        inlined_vid_def_id == v.did ||
             ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid))
     }).unwrap_or_else(|| {
         ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid))
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 5988f95aedf..a7bb4043e7d 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -13,6 +13,7 @@ use back::abi;
 use llvm;
 use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
 use llvm::{InternalLinkage, ValueRef, Bool, True};
+use metadata::cstore::LOCAL_CRATE;
 use middle::{check_const, def};
 use middle::const_eval::{self, ConstVal};
 use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
@@ -25,7 +26,7 @@ use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
 use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
 use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::const_eval::eval_const_expr_partial;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
 use trans::common::*;
@@ -782,7 +783,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         hir::ExprPath(..) => {
             let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
             match def {
-                def::DefLocal(id) => {
+                def::DefLocal(_, id) => {
                     if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
                         val
                     } else {
@@ -876,9 +877,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         hir::ExprClosure(_, ref decl, ref body) => {
             match ety.sty {
-                ty::TyClosure(_, ref substs) => {
+                ty::TyClosure(def_id, ref substs) => {
                     closure::trans_closure_expr(closure::Dest::Ignore(cx), decl,
-                                                body, e.id, substs);
+                                                body, e.id, def_id, substs);
                 }
                 _ =>
                     cx.sess().span_bug(
@@ -959,6 +960,9 @@ fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             did: DefId,
                             ty: Ty<'tcx>)
                             -> ValueRef {
-    if did.is_local() { return base::get_item_val(ccx, did.node) }
-    base::trans_external_path(ccx, did, ty)
+    if let Some(node_id) = ccx.tcx().map.as_local_node_id(did) {
+        base::get_item_val(ccx, node_id)
+    } else {
+        base::trans_external_path(ccx, did, ty)
+    }
 }
diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs
index 1d35b51a5f8..a921bbbc43e 100644
--- a/src/librustc_trans/trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/trans/debuginfo/metadata.rs
@@ -324,8 +324,8 @@ impl<'tcx> TypeMap<'tcx> {
                                             output: &mut String) {
             // First, find out the 'real' def_id of the type. Items inlined from
             // other crates have to be mapped back to their source.
-            let source_def_id = if def_id.is_local() {
-                match cx.external_srcs().borrow().get(&def_id.node).cloned() {
+            let source_def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
+                match cx.external_srcs().borrow().get(&node_id).cloned() {
                     Some(source_def_id) => {
                         // The given def_id identifies the inlined copy of a
                         // type definition, let's take the source of the copy.
@@ -346,7 +346,7 @@ impl<'tcx> TypeMap<'tcx> {
 
             output.push_str(crate_hash.as_str());
             output.push_str("/");
-            output.push_str(&format!("{:x}", def_id.node));
+            output.push_str(&format!("{:x}", def_id.index.as_usize()));
 
             // Maybe check that there is no self type here.
 
@@ -1887,7 +1887,8 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     let is_local_to_unit = is_node_local_to_unit(cx, node_id);
     let variable_type = cx.tcx().node_id_to_type(node_id);
     let type_metadata = type_metadata(cx, variable_type, span);
-    let namespace_node = namespace_for_item(cx, DefId::local(node_id));
+    let node_def_id = cx.tcx().map.local_def_id(node_id);
+    let namespace_node = namespace_for_item(cx, node_def_id);
     let var_name = name.to_string();
     let linkage_name =
         namespace_node.mangled_name_of_contained_item(&var_name[..]);
diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs
index ebd2b7ea418..a08f33c8899 100644
--- a/src/librustc_trans/trans/debuginfo/mod.rs
+++ b/src/librustc_trans/trans/debuginfo/mod.rs
@@ -351,7 +351,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // somehow (storing a path in the hir_map, or construct a path using the
     // enclosing function).
     let (linkage_name, containing_scope) = if has_path {
-        let namespace_node = namespace_for_item(cx, DefId::local(fn_ast_id));
+        let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id);
+        let namespace_node = namespace_for_item(cx, fn_ast_def_id);
         let linkage_name = namespace_node.mangled_name_of_contained_item(
             &function_name[..]);
         let containing_scope = namespace_node.scope;
diff --git a/src/librustc_trans/trans/debuginfo/utils.rs b/src/librustc_trans/trans/debuginfo/utils.rs
index 09d014a3382..276f9936ac5 100644
--- a/src/librustc_trans/trans/debuginfo/utils.rs
+++ b/src/librustc_trans/trans/debuginfo/utils.rs
@@ -99,12 +99,9 @@ pub fn assert_type_for_node_id(cx: &CrateContext,
 pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
                                    -> (DIScope, Span) {
     let containing_scope = namespace_for_item(cx, def_id).scope;
-    let definition_span = if def_id.is_local() {
-        cx.tcx().map.span(def_id.node)
-    } else {
-        // For external items there is no span information
-        codemap::DUMMY_SP
-    };
+    let definition_span = cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP /* (1) */ );
+
+    // (1) For external items there is no span information
 
     (containing_scope, definition_span)
 }
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 722089e42f9..8d57c24ca90 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -923,13 +923,13 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let const_ty = expr_ty(bcx, ref_expr);
 
             // For external constants, we don't inline.
-            let val = if did.is_local() {
+            let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
                 // Case 1.
 
                 // The LLVM global has the type of its initializer,
                 // which may not be equal to the enum's type for
                 // non-C-like enums.
-                let val = base::get_item_val(bcx.ccx(), did.node);
+                let val = base::get_item_val(bcx.ccx(), node_id);
                 let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
                 PointerCast(bcx, val, pty)
             } else {
@@ -1195,14 +1195,23 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
                 Ignore => closure::Dest::Ignore(bcx.ccx())
             };
-            let substs = match expr_ty(bcx, expr).sty {
-                ty::TyClosure(_, ref substs) => substs,
+
+            // NB. To get the id of the closure, we don't use
+            // `local_def_id(id)`, but rather we extract the closure
+            // def-id from the expr's type. This is because this may
+            // be an inlined expression from another crate, and we
+            // want to get the ORIGINAL closure def-id, since that is
+            // the key we need to find the closure-kind and
+            // closure-type etc.
+            let (def_id, substs) = match expr_ty(bcx, expr).sty {
+                ty::TyClosure(def_id, ref substs) => (def_id, substs),
                 ref t =>
                     bcx.tcx().sess.span_bug(
                         expr.span,
                         &format!("closure expr without closure type: {:?}", t)),
             };
-            closure::trans_closure_expr(dest, decl, body, expr.id, substs).unwrap_or(bcx)
+
+            closure::trans_closure_expr(dest, decl, body, expr.id, def_id, substs).unwrap_or(bcx)
         }
         hir::ExprCall(ref f, ref args) => {
             if bcx.tcx().is_method_call(expr.id) {
@@ -1358,7 +1367,7 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let _icx = push_ctxt("trans_local_var");
 
     match def {
-        def::DefUpvar(nid, _, _) => {
+        def::DefUpvar(_, nid, _, _) => {
             // Can't move upvars, so this is never a ZeroMemLastUse.
             let local_ty = node_id_type(bcx, nid);
             let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
@@ -1372,7 +1381,7 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 }
             }
         }
-        def::DefLocal(nid) => {
+        def::DefLocal(_, nid) => {
             let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
                 Some(&v) => v,
                 None => {
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index 0310a8a6041..6b9f1559d37 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -29,9 +29,9 @@ use trans::type_of::*;
 use trans::type_of;
 use middle::ty::{self, Ty};
 use middle::subst::Substs;
-use rustc::front::map as hir_map;
 
 use std::cmp;
+use std::iter::once;
 use libc::c_uint;
 use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
 use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
@@ -610,10 +610,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let t = tcx.node_id_to_type(id);
         let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
 
-        let ps = ccx.tcx().map.with_path(id, |path| {
-            let abi = Some(hir_map::PathName(special_idents::clownshoe_abi.name));
-            link::mangle(path.chain(abi), hash)
-        });
+        let path =
+            tcx.map.def_path_from_id(id)
+                   .into_iter()
+                   .map(|e| e.data.as_interned_str())
+                   .chain(once(special_idents::clownshoe_abi.name.as_str()));
+        let ps = link::mangle(path, hash);
 
         // Compute the type that the function would have if it were just a
         // normal Rust function. This will be the type of the wrappee fn.
diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs
index 22d624be6fc..b8f75df8c11 100644
--- a/src/librustc_trans/trans/inline.rs
+++ b/src/librustc_trans/trans/inline.rs
@@ -30,7 +30,8 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId)
             // Already inline
             debug!("instantiate_inline({}): already inline as node id {}",
                    ccx.tcx().item_path_str(fn_id), node_id);
-            return Some(DefId::local(node_id));
+            let node_def_id = ccx.tcx().map.local_def_id(node_id);
+            return Some(node_def_id);
         }
         Some(&None) => {
             return None; // Not inlinable
@@ -43,7 +44,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId)
     let csearch_result =
         csearch::maybe_get_item_ast(
             ccx.tcx(), fn_id,
-            Box::new(|a,b,c,d| astencode::decode_inlined_item(a, b, c, d)));
+            Box::new(astencode::decode_inlined_item));
 
     let inline_id = match csearch_result {
         csearch::FoundAst::NotFound => {
@@ -144,8 +145,9 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId)
             // reuse that code, it needs to be able to look up the traits for
             // inlined items.
             let ty_trait_item = ccx.tcx().impl_or_trait_item(fn_id).clone();
+            let trait_item_def_id = ccx.tcx().map.local_def_id(trait_item.id);
             ccx.tcx().impl_or_trait_items.borrow_mut()
-                     .insert(DefId::local(trait_item.id), ty_trait_item);
+                     .insert(trait_item_def_id, ty_trait_item);
 
             // If this is a default method, we can't look up the
             // impl type. But we aren't going to translate anyways, so
@@ -185,12 +187,13 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId)
         }
     };
 
-    Some(DefId::local(inline_id))
+    let inline_def_id = ccx.tcx().map.local_def_id(inline_id);
+    Some(inline_def_id)
 }
 
 pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId)
     -> Option<DefId> {
-    if fn_id.is_local() {
+    if let Some(_) = ccx.tcx().map.as_local_node_id(fn_id) {
         Some(fn_id)
     } else {
         instantiate_inline(ccx, fn_id)
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index df0323350fd..33f798be85e 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -38,7 +38,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 fn_id: DefId,
                                 psubsts: &'tcx subst::Substs<'tcx>,
                                 ref_id: Option<ast::NodeId>)
-    -> (ValueRef, Ty<'tcx>, bool) {
+                                -> (ValueRef, Ty<'tcx>, bool) {
     debug!("monomorphic_fn(\
             fn_id={:?}, \
             real_substs={:?}, \
@@ -49,6 +49,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
 
+    // we can only monomorphize things in this crate (or inlined into it)
+    let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap();
+
     let _icx = push_ctxt("monomorphic_fn");
 
     let hash_id = MonoId {
@@ -82,7 +85,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let map_node = session::expect(
         ccx.sess(),
-        ccx.tcx().map.find(fn_id.node),
+        ccx.tcx().map.find(fn_node_id),
         || {
             format!("while monomorphizing {:?}, couldn't find it in \
                      the item map (may have attempted to monomorphize \
@@ -91,10 +94,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         });
 
     if let hir_map::NodeForeignItem(_) = map_node {
-        let abi = ccx.tcx().map.get_foreign_abi(fn_id.node);
+        let abi = ccx.tcx().map.get_foreign_abi(fn_node_id);
         if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic {
             // Foreign externs don't have to be monomorphized.
-            return (get_item_val(ccx, fn_id.node), mono_ty, true);
+            return (get_item_val(ccx, fn_node_id), mono_ty, true);
         }
     }
 
@@ -107,11 +110,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             Some(&d) => d, None => 0
         };
 
+        debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1);
+
         // Random cut-off -- code that needs to instantiate the same function
         // recursively more than thirty times can probably safely be assumed
         // to be causing an infinite expansion.
         if depth > ccx.sess().recursion_limit.get() {
-            ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node),
+            ccx.sess().span_fatal(ccx.tcx().map.span(fn_node_id),
                 "reached the recursion limit during monomorphization");
         }
 
@@ -125,9 +130,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         mono_ty.hash(&mut state);
 
         hash = format!("h{}", state.finish());
-        ccx.tcx().map.with_path(fn_id.node, |path| {
-            exported_name(path, &hash[..])
-        })
+        let path = ccx.tcx().map.def_path_from_id(fn_node_id);
+        exported_name(path, &hash[..])
     };
 
     debug!("monomorphize_fn mangled to {}", s);
@@ -136,7 +140,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let mut hash_id = Some(hash_id);
     let mut mk_lldecl = |abi: abi::Abi| {
         let lldecl = if abi != abi::Rust {
-            foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
+            foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s)
         } else {
             // FIXME(nagisa): perhaps needs a more fine grained selection? See
             // setup_lldecl below.
@@ -178,10 +182,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                   if needs_body {
                       if abi != abi::Rust {
                           foreign::trans_rust_fn_with_foreign_abi(
-                              ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
+                              ccx, &**decl, &**body, &[], d, psubsts, fn_node_id,
                               Some(&hash[..]));
                       } else {
-                          trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
+                          trans_fn(ccx, &**decl, &**body, d, psubsts, fn_node_id, &[]);
                       }
                   }
 
@@ -193,11 +197,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             }
         }
         hir_map::NodeVariant(v) => {
-            let variant = inlined_variant_def(ccx, fn_id.node);
+            let variant = inlined_variant_def(ccx, fn_node_id);
             assert_eq!(v.node.name, variant.name);
             let d = mk_lldecl(abi::Rust);
             attributes::inline(d, attributes::InlineAttr::Hint);
-            trans_enum_variant(ccx, fn_id.node, variant.disr_val, psubsts, d);
+            trans_enum_variant(ccx, fn_node_id, variant.disr_val, psubsts, d);
             d
         }
         hir_map::NodeImplItem(impl_item) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7b2bbbcc4a9..dd15c132560 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -52,7 +52,7 @@ use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_project
 use middle::const_eval::{self, ConstVal};
 use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::resolve_lifetime as rl;
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
@@ -167,12 +167,13 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime)
         }
 
         Some(&rl::DefLateBoundRegion(debruijn, id)) => {
-            ty::ReLateBound(debruijn, ty::BrNamed(DefId::local(id), lifetime.name))
+            ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name))
         }
 
         Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
+            let def_id = tcx.map.local_def_id(id);
             ty::ReEarlyBound(ty::EarlyBoundRegion {
-                param_id: id,
+                def_id: def_id,
                 space: space,
                 index: index,
                 name: lifetime.name
@@ -182,7 +183,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime)
         Some(&rl::DefFreeRegion(scope, id)) => {
             ty::ReFree(ty::FreeRegion {
                     scope: tcx.region_maps.item_extent(scope.node_id),
-                    bound_region: ty::BrNamed(DefId::local(id),
+                    bound_region: ty::BrNamed(tcx.map.local_def_id(id),
                                               lifetime.name)
                 })
         }
@@ -1263,7 +1264,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
             // `Self` in an impl of a trait - we have a concrete self type and a
             // trait reference.
-            let trait_ref = tcx.impl_trait_ref(DefId::local(impl_id)).unwrap();
+            let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
             let trait_ref = if let Some(free_substs) = this.get_free_substs() {
                 trait_ref.subst(tcx, free_substs)
             } else {
@@ -1290,9 +1291,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             }
         }
         (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => {
-            assert_eq!(trait_did.krate, LOCAL_CRATE);
+            let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
             match find_bound_for_assoc_item(this,
-                                            trait_did.node,
+                                            trait_node_id,
                                             token::special_idents::type_self.name,
                                             assoc_name,
                                             span) {
@@ -1301,9 +1302,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             }
         }
         (&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => {
-            assert_eq!(param_did.krate, LOCAL_CRATE);
+            let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
             match find_bound_for_assoc_item(this,
-                                            param_did.node,
+                                            param_node_id,
                                             param_name,
                                             assoc_name,
                                             span) {
@@ -1324,15 +1325,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
     let trait_did = bound.0.def_id;
     let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
 
-    let item_did = if trait_did.is_local() {
+    let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) {
         // `ty::trait_items` used below requires information generated
         // by type collection, which may be in progress at this point.
-        match tcx.map.expect_item(trait_did.node).node {
+        match tcx.map.expect_item(trait_id).node {
             hir::ItemTrait(_, _, _, ref trait_items) => {
                 let item = trait_items.iter()
                                       .find(|i| i.name == assoc_name)
                                       .expect("missing associated type");
-                DefId::local(item.id)
+                tcx.map.local_def_id(item.id)
             }
             _ => unreachable!()
         }
@@ -1506,11 +1507,12 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             // we don't have the trait information around, which is just sad.
 
             if !base_segments.is_empty() {
+                let id_node = tcx.map.as_local_node_id(id).unwrap();
                 span_err!(tcx.sess,
                           span,
                           E0247,
                           "found module name used as a type: {}",
-                          tcx.map.node_to_string(id.node));
+                          tcx.map.node_to_user_string(id_node));
                 return this.tcx().types.err;
             }
 
@@ -1520,10 +1522,10 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             prim_ty_to_ty(tcx, base_segments, prim_ty)
         }
         _ => {
-            let node = def.def_id().node;
+            let id_node = tcx.map.as_local_node_id(def.def_id()).unwrap();
             span_err!(tcx.sess, span, E0248,
                       "found value `{}` used as a type",
-                      tcx.map.path_to_string(node));
+                      tcx.map.path_to_string(id_node));
             return this.tcx().types.err;
         }
     }
@@ -1638,7 +1640,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
             } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
                 // Create some fake resolution that can't possibly be a type.
                 def::PathResolution {
-                    base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+                    base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
                     last_private: LastMod(AllPublic),
                     depth: path.segments.len()
                 }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 546e337d746..8bcff225755 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use middle::def;
-use middle::def_id::DefId;
 use middle::infer;
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
 use middle::pat_util::pat_is_resolved_const;
@@ -202,9 +201,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
                 d
             } else if qself.position == 0 {
+                // This is just a sentinel for finish_resolving_def_to_ty.
+                let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID);
                 def::PathResolution {
-                    // This is just a sentinel for finish_resolving_def_to_ty.
-                    base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+                    base_def: def::DefMod(sentinel),
                     last_private: LastMod(AllPublic),
                     depth: path.segments.len()
                 }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 948b7dd1561..dcecec7007d 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -25,7 +25,8 @@ use super::UnresolvedTypeAction;
 use super::write_call;
 
 use CrateCtxt;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
 use middle::infer;
 use middle::ty::{self, LvaluePreference, Ty};
 use syntax::codemap::Span;
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 82c898214c5..4f7a6395395 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -13,7 +13,6 @@
 use super::{check_fn, Expectation, FnCtxt};
 
 use astconv;
-use middle::def_id::DefId;
 use middle::subst;
 use middle::ty::{self, ToPolyTraitRef, Ty};
 use std::cmp;
@@ -46,7 +45,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                           decl: &'tcx hir::FnDecl,
                           body: &'tcx hir::Block,
                           expected_sig: Option<ty::FnSig<'tcx>>) {
-    let expr_def_id = DefId::local(expr.id);
+    let expr_def_id = fcx.tcx().map.local_def_id(expr.id);
 
     debug!("check_closure opt_kind={:?} expected_sig={:?}",
            opt_kind,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 6d8b757d167..c46f386af27 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -169,8 +169,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     // Create a parameter environment that represents the implementation's
     // method.
-    let impl_param_env =
-        ty::ParameterEnvironment::for_item(tcx, impl_m.def_id.node);
+    let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id);
 
     // Create mapping from impl to skolemized.
     let impl_to_skol_substs = &impl_param_env.free_substs;
@@ -428,8 +428,8 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     // Create a parameter environment that represents the implementation's
     // method.
-    let impl_param_env =
-        ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
+    let impl_c_node_id = tcx.map.as_local_node_id(impl_c.def_id).unwrap();
+    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
 
     // Create mapping from impl to skolemized.
     let impl_to_skol_substs = &impl_param_env.free_substs;
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index a8c77f863b7..870a81e510e 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -10,7 +10,7 @@
 
 use check::regionck::{self, Rcx};
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use middle::infer;
 use middle::region;
@@ -77,11 +77,12 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     drop_impl_ty: &ty::Ty<'tcx>,
     self_type_did: DefId) -> Result<(), ()>
 {
-    assert!(drop_impl_did.is_local() && self_type_did.is_local());
+    let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap();
+    let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
 
     // check that the impl type can be made to match the trait type.
 
-    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node);
+    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
     let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true);
 
     let named_type = tcx.lookup_item_type(self_type_did).ty;
@@ -96,7 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
                                    named_type, fresh_impl_self_ty) {
         span_err!(tcx.sess, drop_impl_span, E0366,
                   "Implementations of Drop cannot be specialized");
-        let item_span = tcx.map.span(self_type_did.node);
+        let item_span = tcx.map.span(self_type_node_id);
         tcx.sess.span_note(item_span,
                            "Use same sequence of generic type and region \
                             parameters that is on the struct/enum definition");
@@ -110,7 +111,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     }
 
     let free_regions = FreeRegionMap::new();
-    infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node);
+    infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
     Ok(())
 }
 
@@ -158,7 +159,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     // absent. So we report an error that the Drop impl injected a
     // predicate that is not present on the struct definition.
 
-    assert_eq!(self_type_did.krate, LOCAL_CRATE);
+    let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
 
     let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
 
@@ -195,7 +196,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
         // repeated `contains` calls.
 
         if !assumptions_in_impl_context.contains(&predicate) {
-            let item_span = tcx.map.span(self_type_did.node);
+            let item_span = tcx.map.span(self_type_node_id);
             span_err!(tcx.sess, drop_impl_span, E0367,
                       "The requirement `{}` is added only by the Drop impl.", predicate);
             tcx.sess.span_note(item_span,
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 8a114473e3c..4afc610f63e 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -13,7 +13,6 @@
 
 use astconv::AstConv;
 use intrinsics;
-use middle::def_id::DefId;
 use middle::subst;
 use middle::ty::FnSig;
 use middle::ty::{self, Ty};
@@ -43,7 +42,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, it: &hir::ForeignItem,
             variadic: false,
         }),
     }));
-    let i_ty = tcx.lookup_item_type(DefId::local(it.id));
+    let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id));
     let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
     if i_n_tps != n_tps {
         span_err!(tcx.sess, it.span, E0094,
@@ -365,7 +364,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
     };
 
     let tcx = ccx.tcx;
-    let i_ty = tcx.lookup_item_type(DefId::local(it.id));
+    let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id));
     let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
     let name = it.name.as_str();
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 821615d0341..e10175c81aa 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -15,6 +15,7 @@ use CrateCtxt;
 
 use astconv::AstConv;
 use check::{self, FnCtxt};
+use front::map as hir_map;
 use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags};
 use middle::def;
 use middle::def_id::DefId;
@@ -364,13 +365,11 @@ impl PartialOrd for TraitInfo {
 }
 impl Ord for TraitInfo {
     fn cmp(&self, other: &TraitInfo) -> Ordering {
-        // accessible traits are more important/relevant than
-        // inaccessible ones, local crates are more important than
-        // remote ones (local: cnum == 0), and NodeIds just for
-        // totality.
+        // local crates are more important than remote ones (local:
+        // cnum == 0), and otherwise we throw in the defid for totality
 
-        let lhs = (other.def_id.krate, other.def_id.node);
-        let rhs = (self.def_id.krate, self.def_id.node);
+        let lhs = (other.def_id.krate, other.def_id);
+        let rhs = (self.def_id.krate, self.def_id);
         lhs.cmp(&rhs)
     }
 }
@@ -385,14 +384,16 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
         // Crate-local:
         //
         // meh.
-        struct Visitor<'a> {
+        struct Visitor<'a, 'tcx:'a> {
+            map: &'a hir_map::Map<'tcx>,
             traits: &'a mut AllTraitsVec,
         }
-        impl<'v, 'a> visit::Visitor<'v> for Visitor<'a> {
+        impl<'v, 'a, 'tcx> visit::Visitor<'v> for Visitor<'a, 'tcx> {
             fn visit_item(&mut self, i: &'v hir::Item) {
                 match i.node {
                     hir::ItemTrait(..) => {
-                        self.traits.push(TraitInfo::new(DefId::local(i.id)));
+                        let def_id = self.map.local_def_id(i.id);
+                        self.traits.push(TraitInfo::new(def_id));
                     }
                     _ => {}
                 }
@@ -400,6 +401,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
             }
         }
         visit::walk_crate(&mut Visitor {
+            map: &ccx.tcx.map,
             traits: &mut traits
         }, ccx.tcx.map.krate());
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e62f5b82e7a..08a0f1c7e87 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -83,9 +83,10 @@ use self::TupleArgumentsFlag::*;
 use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
 use check::_match::pat_ctxt;
 use fmt_macros::{Parser, Piece, Position};
+use metadata::cstore::LOCAL_CRATE;
 use middle::astconv_util::prohibit_type_params;
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::infer;
 use middle::infer::type_variable;
 use middle::pat_util::{self, pat_id_map};
@@ -687,7 +688,7 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
 
     check_representable(tcx, span, id, "struct");
 
-    if tcx.lookup_simd(DefId::local(id)) {
+    if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
         check_simd(tcx, span, id);
     }
 }
@@ -695,7 +696,7 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
 pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_type(it.id={}, it.name={})",
            it.id,
-           ccx.tcx.item_path_str(DefId::local(it.id)));
+           ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
@@ -710,7 +711,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
       hir::ItemFn(..) => {} // entirely within check_item_body
       hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
-          match ccx.tcx.impl_trait_ref(DefId::local(it.id)) {
+          match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) {
               Some(impl_trait_ref) => {
                 check_impl_items_against_trait(ccx,
                                                it.span,
@@ -741,7 +742,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
             }
         } else {
             for item in &m.items {
-                let pty = ccx.tcx.lookup_item_type(DefId::local(item.id));
+                let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id));
                 if !pty.generics.types.is_empty() {
                     span_err!(ccx.tcx.sess, item.span, E0044,
                         "foreign items may not have type parameters");
@@ -763,18 +764,18 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
 pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_body(it.id={}, it.name={})",
            it.id,
-           ccx.tcx.item_path_str(DefId::local(it.id)));
+           ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
       hir::ItemFn(ref decl, _, _, _, _, ref body) => {
-        let fn_pty = ccx.tcx.lookup_item_type(DefId::local(it.id));
+        let fn_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
         let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
         check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
       }
       hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
 
-        let impl_pty = ccx.tcx.lookup_item_type(DefId::local(it.id));
+        let impl_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
 
         for impl_item in impl_items {
             match impl_item.node {
@@ -792,7 +793,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         }
       }
       hir::ItemTrait(_, _, _, ref trait_items) => {
-        let trait_def = ccx.tcx.lookup_trait_def(DefId::local(it.id));
+        let trait_def = ccx.tcx.lookup_trait_def(ccx.tcx.map.local_def_id(it.id));
         for trait_item in trait_items {
             match trait_item.node {
                 hir::ConstTraitItem(_, Some(ref expr)) => {
@@ -911,7 +912,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
     for impl_item in impl_items {
-        let ty_impl_item = ccx.tcx.impl_or_trait_item(DefId::local(impl_item.id));
+        let ty_impl_item = ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(impl_item.id));
         let ty_trait_item = trait_items.iter()
             .find(|ac| ac.name() == ty_impl_item.name())
             .unwrap_or_else(|| {
@@ -1953,7 +1954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .unwrap_or(type_variable::Default {
                                 ty: self.infcx().next_ty_var(),
                                 origin_span: codemap::DUMMY_SP,
-                                def_id: DefId::local(0) // what do I put here?
+                                def_id: self.tcx().map.local_def_id(0) // what do I put here?
                             });
 
                     // This is to ensure that we elimnate any non-determinism from the error
@@ -3356,7 +3357,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
           } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
                 // Create some fake resolution that can't possibly be a type.
                 def::PathResolution {
-                    base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+                    base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
                     last_private: LastMod(AllPublic),
                     depth: path.segments.len()
                 }
@@ -4108,7 +4109,7 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     let inh = static_inherited_fields(ccx, &tables);
     let rty = ccx.tcx.node_id_to_type(id);
     let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
-    let declty = fcx.ccx.tcx.lookup_item_type(DefId::local(id)).ty;
+    let declty = fcx.ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
     check_const_with_ty(&fcx, sp, e, declty);
 }
 
@@ -4124,8 +4125,13 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     check_expr_with_hint(fcx, e, declty);
     demand::coerce(fcx, e.span, declty, e);
-    fcx.select_all_obligations_or_error();
+
+    fcx.select_all_obligations_and_apply_defaults();
+    upvar::closure_analyze_const(&fcx, e);
+    fcx.select_obligations_where_possible();
     fcx.check_casts();
+    fcx.select_all_obligations_or_error();
+
     regionck::regionck_expr(fcx, e);
     writeback::resolve_type_vars_in_expr(fcx, e);
 }
@@ -4236,7 +4242,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             }
         }
 
-        let def_id = DefId::local(id);
+        let def_id = ccx.tcx.map.local_def_id(id);
 
         let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
         for (v, variant) in vs.iter().zip(variants.iter()) {
@@ -4247,7 +4253,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                 Some(i) => {
                     span_err!(ccx.tcx.sess, v.span, E0081,
                         "discriminant value `{}` already exists", disr_vals[i]);
-                    span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node),
+                    let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
+                    span_note!(ccx.tcx.sess, ccx.tcx.map.span(variant_i_node_id),
                         "conflicting discriminant here")
                 }
                 None => {}
@@ -4274,8 +4281,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         }
     }
 
-    let hint = *ccx.tcx.lookup_repr_hints(DefId { krate: LOCAL_CRATE, node: id })
-        .get(0).unwrap_or(&attr::ReprAny);
+    let def_id = ccx.tcx.map.local_def_id(id);
+    let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
 
     if hint != attr::ReprAny && vs.len() <= 1 {
         if vs.len() == 1 {
@@ -4298,7 +4305,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                 defn: def::Def)
                                                 -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
     match defn {
-        def::DefLocal(nid) | def::DefUpvar(nid, _, _) => {
+        def::DefLocal(_, nid) | def::DefUpvar(_, nid, _, _) => {
             let typ = fcx.local_ty(sp, nid);
             (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
              ty::GenericPredicates::empty())
@@ -4316,7 +4323,6 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         def::DefMod(..) |
         def::DefForeignMod(..) |
         def::DefUse(..) |
-        def::DefRegion(..) |
         def::DefLabel(..) |
         def::DefSelfTy(..) => {
             fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
@@ -4487,7 +4493,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         def::DefForeignMod(..) |
         def::DefLocal(..) |
         def::DefUse(..) |
-        def::DefRegion(..) |
         def::DefLabel(..) |
         def::DefUpvar(..) => {
             segment_spaces = vec![None; segments.len()];
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index f9f711a1a63..78d493c8a71 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -43,7 +43,6 @@
 use super::FnCtxt;
 
 use check::demand;
-use middle::def_id::DefId;
 use middle::expr_use_visitor as euv;
 use middle::mem_categorization as mc;
 use middle::ty::{self, Ty};
@@ -73,6 +72,20 @@ pub fn closure_analyze_fn(fcx: &FnCtxt,
     assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
 }
 
+pub fn closure_analyze_const(fcx: &FnCtxt,
+                             body: &hir::Expr)
+{
+    let mut seed = SeedBorrowKind::new(fcx);
+    seed.visit_expr(body);
+    let closures_with_inferred_kinds = seed.closures_with_inferred_kinds;
+
+    let mut adjust = AdjustBorrowKind::new(fcx, &closures_with_inferred_kinds);
+    adjust.visit_expr(body);
+
+    // it's our job to process these.
+    assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty());
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // SEED BORROW KIND
 
@@ -116,7 +129,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
                      capture_clause: hir::CaptureClause,
                      _body: &hir::Block)
     {
-        let closure_def_id = DefId::local(expr.id);
+        let closure_def_id = self.tcx().map.local_def_id(expr.id);
         if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
             self.closures_with_inferred_kinds.insert(expr.id);
             self.fcx.inh.tables.borrow_mut().closure_kinds
@@ -127,7 +140,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
 
         self.tcx().with_freevars(expr.id, |freevars| {
             for freevar in freevars {
-                let var_node_id = freevar.def.local_node_id();
+                let var_node_id = freevar.def.var_id();
                 let upvar_id = ty::UpvarId { var_id: var_node_id,
                                              closure_expr_id: expr.id };
                 debug!("seed upvar_id {:?}", upvar_id);
@@ -215,7 +228,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
 
         // Now we must process and remove any deferred resolutions,
         // since we have a concrete closure kind.
-        let closure_def_id = DefId::local(id);
+        let closure_def_id = self.fcx.tcx().map.local_def_id(id);
         if self.closures_with_inferred_kinds.contains(&id) {
             let mut deferred_call_resolutions =
                 self.fcx.remove_deferred_call_resolutions(closure_def_id);
@@ -236,16 +249,16 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
         tcx.with_freevars(closure_id, |freevars| {
             freevars.iter()
                     .map(|freevar| {
-                        let freevar_def_id = freevar.def.def_id();
-                        let freevar_ty = self.fcx.node_ty(freevar_def_id.node);
+                        let freevar_node_id = freevar.def.var_id();
+                        let freevar_ty = self.fcx.node_ty(freevar_node_id);
                         let upvar_id = ty::UpvarId {
-                            var_id: freevar_def_id.node,
+                            var_id: freevar_node_id,
                             closure_expr_id: closure_id
                         };
                         let capture = self.fcx.infcx().upvar_capture(upvar_id).unwrap();
 
-                        debug!("freevar_def_id={:?} freevar_ty={:?} capture={:?}",
-                               freevar_def_id, freevar_ty, capture);
+                        debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}",
+                               freevar_node_id, freevar_ty, capture);
 
                         match capture {
                             ty::UpvarCapture::ByValue => freevar_ty,
@@ -469,7 +482,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
             return;
         }
 
-        let closure_def_id = DefId::local(closure_id);
+        let closure_def_id = self.fcx.tcx().map.local_def_id(closure_id);
         let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds;
         let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
 
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 70983b89ed5..b5cf069bda6 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -12,7 +12,6 @@ use astconv::AstConv;
 use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck, wfcheck};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 use CrateCtxt;
-use middle::def_id::DefId;
 use middle::region;
 use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
 use middle::traits;
@@ -57,7 +56,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let ccx = self.ccx;
         debug!("check_item_well_formed(it.id={}, it.name={})",
                item.id,
-               ccx.tcx.item_path_str(DefId::local(item.id)));
+               ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id)));
 
         match item.node {
             /// Right now we check that every default trait implementation
@@ -81,7 +80,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 self.check_impl(item);
             }
             hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
-                let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+                let item_def_id = ccx.tcx.map.local_def_id(item.id);
+                let trait_ref = ccx.tcx.impl_trait_ref(item_def_id).unwrap();
                 ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
                 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
                     Some(ty::BoundSend) | Some(ty::BoundSync) => {}
@@ -117,9 +117,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             }
             hir::ItemTrait(_, _, _, ref items) => {
                 let trait_predicates =
-                    ccx.tcx.lookup_predicates(DefId::local(item.id));
+                    ccx.tcx.lookup_predicates(ccx.tcx.map.local_def_id(item.id));
                 reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates);
-                if ccx.tcx.trait_has_default_impl(DefId::local(item.id)) {
+                if ccx.tcx.trait_has_default_impl(ccx.tcx.map.local_def_id(item.id)) {
                     if !items.is_empty() {
                         wfcheck::error_380(ccx, item.span);
                     }
@@ -133,7 +133,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>),
     {
         let ccx = self.ccx;
-        let item_def_id = DefId::local(item.id);
+        let item_def_id = ccx.tcx.map.local_def_id(item.id);
         let type_scheme = ccx.tcx.lookup_item_type(item_def_id);
         let type_predicates = ccx.tcx.lookup_predicates(item_def_id);
         reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
@@ -194,7 +194,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                                                         Some(&mut this.cache));
             debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope);
 
-            let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+            let item_def_id = fcx.tcx().map.local_def_id(item.id);
+            let type_scheme = fcx.tcx().lookup_item_type(item_def_id);
             let item_ty = fcx.instantiate_type_scheme(item.span,
                                                       &fcx.inh
                                                           .infcx
@@ -230,7 +231,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
             // Similarly, obtain an "inside" reference to the trait
             // that the impl implements.
-            let trait_ref = match fcx.tcx().impl_trait_ref(DefId::local(item.id)) {
+            let trait_ref = match fcx.tcx().impl_trait_ref(fcx.tcx().map.local_def_id(item.id)) {
                 None => { return; }
                 Some(t) => { t }
             };
@@ -279,7 +280,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                                      item: &hir::Item,
                                      ast_generics: &hir::Generics)
     {
-        let item_def_id = DefId::local(item.id);
+        let item_def_id = self.tcx().map.local_def_id(item.id);
         let ty_predicates = self.tcx().lookup_predicates(item_def_id);
         let variances = self.tcx().item_variances(item_def_id);
 
@@ -431,7 +432,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         match fk {
             FnKind::Closure | FnKind::ItemFn(..) => {}
             FnKind::Method(..) => {
-                match self.tcx().impl_or_trait_item(DefId::local(id)) {
+                match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(id)) {
                     ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
                         reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics)
                     }
@@ -444,7 +445,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
         if let hir::MethodTraitItem(_, None) = trait_item.node {
-            match self.tcx().impl_or_trait_item(DefId::local(trait_item.id)) {
+            match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(trait_item.id)) {
                 ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
                     reject_non_type_param_bounds(
                         self.tcx(),
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 2c6879891b1..b8d942ad227 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -63,7 +63,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let ccx = self.ccx;
         debug!("check_item_well_formed(it.id={}, it.name={})",
                item.id,
-               ccx.tcx.item_path_str(DefId::local(item.id)));
+               ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id)));
 
         match item.node {
             /// Right now we check that every default trait implementation
@@ -90,7 +90,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
-                let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+                let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
                 ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
                 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
                     Some(ty::BoundSend) | Some(ty::BoundSync) => {}
@@ -137,7 +137,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
             let free_id = fcx.inh.infcx.parameter_environment.free_id;
 
-            let item = fcx.tcx().impl_or_trait_item(DefId::local(item_id));
+            let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
 
             let mut implied_bounds = match item.container() {
                 ty::TraitContainer(_) => vec![],
@@ -216,7 +216,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             }
 
             let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id));
+            let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
@@ -228,7 +228,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                    item: &hir::Item,
                    items: &[P<hir::TraitItem>])
     {
-        let trait_def_id = DefId::local(item.id);
+        let trait_def_id = self.tcx().map.local_def_id(item.id);
 
         if self.ccx.tcx.trait_has_default_impl(trait_def_id) {
             if !items.is_empty() {
@@ -251,7 +251,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     {
         self.with_item_fcx(item, |fcx, this| {
             let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+            let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
             let bare_fn_ty = match item_ty.sty {
                 ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty,
@@ -260,7 +260,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 }
             };
 
-            let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id));
+            let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
 
             let mut implied_bounds = vec![];
@@ -276,7 +276,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         debug!("check_item_type: {:?}", item);
 
         self.with_item_fcx(item, |fcx, this| {
-            let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+            let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span,
                                                       &fcx.inh
                                                           .infcx
@@ -299,7 +299,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 
         self.with_item_fcx(item, |fcx, this| {
             let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
-            let item_def_id = DefId::local(item.id);
+            let item_def_id = fcx.tcx().map.local_def_id(item.id);
 
             match *ast_trait_ref {
                 Some(ref ast_trait_ref) => {
@@ -328,7 +328,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
             this.check_where_clauses(fcx, item.span, &predicates);
 
-            impl_implied_bounds(fcx, DefId::local(item.id), item.span)
+            impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span)
         });
     }
 
@@ -386,7 +386,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                                      item: &hir::Item,
                                      ast_generics: &hir::Generics)
     {
-        let item_def_id = DefId::local(item.id);
+        let item_def_id = self.tcx().map.local_def_id(item.id);
         let ty_predicates = self.tcx().lookup_predicates(item_def_id);
         let variances = self.tcx().item_variances(item_def_id);
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 68c0f130c20..16884e76a8e 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -388,8 +388,8 @@ impl ResolveReason {
                 tcx.expr_span(upvar_id.closure_expr_id)
             }
             ResolvingClosure(did) => {
-                if did.is_local() {
-                    tcx.expr_span(did.node)
+                if let Some(node_id) = tcx.map.as_local_node_id(did) {
+                    tcx.expr_span(node_id)
                 } else {
                     DUMMY_SP
                 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 714bd1d2bc5..b3ec10a8941 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -16,7 +16,7 @@
 // mappings. That mapping code resides here.
 
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::lang_items::UnsizeTraitLangItem;
 use middle::subst::{self, Subst};
 use middle::traits;
@@ -138,7 +138,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
 
     fn check_implementation(&self, item: &Item) {
         let tcx = self.crate_context.tcx;
-        let impl_did = DefId::local(item.id);
+        let impl_did = tcx.map.local_def_id(item.id);
         let self_type = tcx.lookup_item_type(impl_did);
 
         // If there are no traits, then this implementation must have a
@@ -194,15 +194,16 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
         match item.node {
             ItemImpl(_, _, _, _, _, ref impl_items) => {
                 impl_items.iter().map(|impl_item| {
+                    let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id);
                     match impl_item.node {
                         hir::ConstImplItem(..) => {
-                            ConstTraitItemId(DefId::local(impl_item.id))
+                            ConstTraitItemId(impl_def_id)
                         }
                         hir::MethodImplItem(..) => {
-                            MethodTraitItemId(DefId::local(impl_item.id))
+                            MethodTraitItemId(impl_def_id)
                         }
                         hir::TypeImplItem(_) => {
-                            TypeTraitItemId(DefId::local(impl_item.id))
+                            TypeTraitItemId(impl_def_id)
                         }
                     }
                 }).collect()
@@ -245,17 +246,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
                 }
                 _ => {
                     // Destructors only work on nominal types.
-                    if impl_did.is_local() {
-                        {
-                            match tcx.map.find(impl_did.node) {
-                                Some(hir_map::NodeItem(item)) => {
-                                    span_err!(tcx.sess, item.span, E0120,
-                                        "the Drop trait may only be implemented on structures");
-                                }
-                                _ => {
-                                    tcx.sess.bug("didn't find impl in ast \
-                                                  map");
-                                }
+                    if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
+                        match tcx.map.find(impl_node_id) {
+                            Some(hir_map::NodeItem(item)) => {
+                                span_err!(tcx.sess, item.span, E0120,
+                                          "the Drop trait may only be implemented on structures");
+                            }
+                            _ => {
+                                tcx.sess.bug("didn't find impl in ast \
+                                              map");
                             }
                         }
                     } else {
@@ -281,18 +280,20 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("check_implementations_of_copy: impl_did={:?}",
                    impl_did);
 
-            if impl_did.krate != LOCAL_CRATE {
+            let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+                n
+            } else {
                 debug!("check_implementations_of_copy(): impl not in this \
                         crate");
                 return
-            }
+            };
 
             let self_type = tcx.lookup_item_type(impl_did);
             debug!("check_implementations_of_copy: self_type={:?} (bound)",
                    self_type);
 
-            let span = tcx.map.span(impl_did.node);
-            let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
+            let span = tcx.map.span(impl_node_id);
+            let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
             let self_type = self_type.ty.subst(tcx, &param_env.free_substs);
             assert!(!self_type.has_escaping_regions());
 
@@ -350,11 +351,13 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
                    impl_did);
 
-            if impl_did.krate != LOCAL_CRATE {
+            let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+                n
+            } else {
                 debug!("check_implementations_of_coerce_unsized(): impl not \
                         in this crate");
                 return;
-            }
+            };
 
             let source = tcx.lookup_item_type(impl_did).ty;
             let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
@@ -362,8 +365,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
                    source, target);
 
-            let span = tcx.map.span(impl_did.node);
-            let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
+            let span = tcx.map.span(impl_node_id);
+            let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
             let source = source.subst(tcx, &param_env.free_substs);
             let target = target.subst(tcx, &param_env.free_substs);
             assert!(!source.has_escaping_regions());
@@ -463,7 +466,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
 
             // Register an obligation for `A: Trait<B>`.
-            let cause = traits::ObligationCause::misc(span, impl_did.node);
+            let cause = traits::ObligationCause::misc(span, impl_node_id);
             let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id,
                                                             0, source, vec![target]);
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
@@ -477,7 +480,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             let mut free_regions = FreeRegionMap::new();
             free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment
                                                                         .caller_bounds);
-            infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node);
+            infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
 
             if let Some(kind) = kind {
                 tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 43ae33ac596..f796f7fe9f9 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -11,7 +11,8 @@
 //! Orphan checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
 use middle::traits;
 use middle::ty;
 use syntax::ast;
@@ -63,7 +64,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     /// to prevent inundating the user with a bunch of similar error
     /// reports.
     fn check_item(&self, item: &hir::Item) {
-        let def_id = DefId::local(item.id);
+        let def_id = self.tcx.map.local_def_id(item.id);
         match item.node {
             hir::ItemImpl(_, _, _, None, _, _) => {
                 // For inherent impls, self type must be a nominal type
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 55b5f665d11..706f28f9fe4 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -11,7 +11,8 @@
 //! Overlap: No two impls for the same trait are implemented for the
 //! same type.
 
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
 use middle::traits;
 use middle::ty;
 use middle::infer::{self, new_infer_ctxt};
@@ -111,7 +112,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
             }
         } else if impl2_def_id.krate != LOCAL_CRATE {
             Some((impl1_def_id, impl2_def_id))
-        } else if impl1_def_id.node < impl2_def_id.node {
+        } else if impl1_def_id < impl2_def_id {
             Some((impl1_def_id, impl2_def_id))
         } else {
             Some((impl2_def_id, impl1_def_id))
@@ -164,8 +165,8 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
     }
 
     fn span_of_impl(&self, impl_did: DefId) -> Span {
-        assert_eq!(impl_did.krate, LOCAL_CRATE);
-        self.tcx.map.span(impl_did.node)
+        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
+        self.tcx.map.span(node_id)
     }
 }
 
@@ -177,20 +178,20 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                 // look for another default impl; note that due to the
                 // general orphan/coherence rules, it must always be
                 // in this crate.
-                let impl_def_id = DefId::local(item.id);
+                let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                 match prev_default_impl {
                     Some(prev_id) => {
                         self.report_overlap_error(trait_ref.def_id,
                                                   impl_def_id,
-                                                  DefId::local(prev_id));
+                                                  self.tcx.map.local_def_id(prev_id));
                     }
                     None => { }
                 }
             }
             hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => {
-                let impl_def_id = DefId::local(item.id);
+                let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
                 match trait_ref.self_ty().sty {
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index b739709e622..f7b10b90013 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -11,7 +11,6 @@
 //! Unsafety checker: every impl either implements a trait defined in this
 //! crate or pertains to a type defined in this crate.
 
-use middle::def_id::DefId;
 use middle::ty;
 use rustc_front::visit;
 use rustc_front::hir;
@@ -30,7 +29,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
     fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
                                 unsafety: hir::Unsafety,
                                 polarity: hir::ImplPolarity) {
-        match self.tcx.impl_trait_ref(DefId::local(item.id)) {
+        match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
             None => {
                 // Inherent impl.
                 match unsafety {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a59e6f54c81..da272b52ebc 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -66,7 +66,7 @@ There are some shortcomings in this design:
 
 use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
 use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use constrained_type_params as ctp;
 use middle::lang_items::SizedTraitLangItem;
 use middle::free_region::FreeRegionMap;
@@ -198,7 +198,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
     }
 
     fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
-        let def_id = DefId::local(method_id);
+        let def_id = self.tcx.map.local_def_id(method_id);
         match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
             ty::MethodTraitItem(ref mty) => mty.clone(),
             _ => {
@@ -316,16 +316,16 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
     {
         let tcx = self.tcx;
 
-        if trait_id.krate != LOCAL_CRATE {
-            return tcx.lookup_trait_def(trait_id)
-        }
-
-        let item = match tcx.map.get(trait_id.node) {
-            hir_map::NodeItem(item) => item,
-            _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
-        };
+        if let Some(trait_id) = tcx.map.as_local_node_id(trait_id) {
+            let item = match tcx.map.get(trait_id) {
+                hir_map::NodeItem(item) => item,
+                _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
+            };
 
-        trait_def_of_item(self, &*item)
+            trait_def_of_item(self, &*item)
+        } else {
+            tcx.lookup_trait_def(trait_id)
+        }
     }
 
     /// Ensure that the (transitive) super predicates for
@@ -402,8 +402,8 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
                                            assoc_name: ast::Name)
                                            -> bool
     {
-        if trait_def_id.is_local() {
-            trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name)
+        if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) {
+            trait_defines_associated_type_named(self.ccx, trait_id, assoc_name)
         } else {
             let trait_def = self.tcx().lookup_trait_def(trait_def_id);
             trait_def.associated_type_names.contains(&assoc_name)
@@ -558,10 +558,10 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
         let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
         match path_res.base_def {
             def::DefSelfTy(Some(def_id), None) => {
-                path_res.depth == 0 && def_id.node == param_id
+                path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
             }
             def::DefTyParam(_, _, def_id, _) => {
-                path_res.depth == 0 && def_id == DefId::local(param_id)
+                path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
             }
             _ => {
                 false
@@ -591,7 +591,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
                               sig, untransformed_rcvr_ty);
 
-    let def_id = DefId::local(id);
+    let def_id = ccx.tcx.map.local_def_id(id);
     let ty_method = ty::Method::new(name,
                                     ty_generics,
                                     ty_generic_predicates,
@@ -631,12 +631,12 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     write_ty_to_tcx(ccx.tcx, v.node.id, tt);
 
     /* add the field to the tcache */
-    ccx.tcx.register_item_type(DefId::local(v.node.id),
+    ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(v.node.id),
                                ty::TypeScheme {
                                    generics: struct_generics.clone(),
                                    ty: tt
                                });
-    ccx.tcx.predicates.borrow_mut().insert(DefId::local(v.node.id),
+    ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(v.node.id),
                                            struct_predicates.clone());
 }
 
@@ -648,7 +648,7 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                       ty: ty::Ty<'tcx>,
                                       has_value: bool)
 {
-    ccx.tcx.predicates.borrow_mut().insert(DefId::local(id),
+    ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id),
                                            ty::GenericPredicates::empty());
 
     write_ty_to_tcx(ccx.tcx, id, ty);
@@ -656,13 +656,13 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let associated_const = Rc::new(ty::AssociatedConst {
         name: name,
         vis: vis,
-        def_id: DefId::local(id),
+        def_id: ccx.tcx.map.local_def_id(id),
         container: container,
         ty: ty,
         has_value: has_value
     });
     ccx.tcx.impl_or_trait_items.borrow_mut()
-       .insert(DefId::local(id), ty::ConstTraitItem(associated_const));
+       .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const));
 }
 
 fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -676,11 +676,11 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         name: name,
         vis: vis,
         ty: ty,
-        def_id: DefId::local(id),
+        def_id: ccx.tcx.map.local_def_id(id),
         container: container
     });
     ccx.tcx.impl_or_trait_items.borrow_mut()
-       .insert(DefId::local(id), ty::TypeTraitItem(associated_type));
+       .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type));
 }
 
 fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -751,7 +751,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             let (scheme, predicates) = convert_typed_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, scheme.ty);
             convert_enum_variant_types(ccx,
-                                       tcx.lookup_adt_def_master(DefId::local(it.id)),
+                                       tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)),
                                        scheme,
                                        predicates,
                                        &enum_definition.variants);
@@ -765,7 +765,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             tcx.record_trait_has_default_impl(trait_ref.def_id);
 
-            tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), Some(trait_ref));
+            tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+                                                    Some(trait_ref));
         }
         hir::ItemImpl(_, _,
                       ref generics,
@@ -782,21 +783,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty);
             write_ty_to_tcx(tcx, it.id, selfty);
 
-            tcx.register_item_type(DefId::local(it.id),
+            tcx.register_item_type(ccx.tcx.map.local_def_id(it.id),
                                    TypeScheme { generics: ty_generics.clone(),
                                                 ty: selfty });
-            tcx.predicates.borrow_mut().insert(DefId::local(it.id),
+            tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
                                                ty_predicates.clone());
             if let &Some(ref ast_trait_ref) = opt_trait_ref {
                 tcx.impl_trait_refs.borrow_mut().insert(
-                    DefId::local(it.id),
+                    ccx.tcx.map.local_def_id(it.id),
                     Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
                                                              &ExplicitRscope,
                                                              ast_trait_ref,
                                                              Some(selfty)))
                         );
             } else {
-                tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), None);
+                tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), None);
             }
 
 
@@ -838,12 +839,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                 if let hir::ConstImplItem(ref ty, _) = impl_item.node {
                     let ty = ccx.icx(&ty_predicates)
                                 .to_ty(&ExplicitRscope, &*ty);
-                    tcx.register_item_type(DefId::local(impl_item.id),
+                    tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id),
                                            TypeScheme {
                                                generics: ty_generics.clone(),
                                                ty: ty,
                                            });
-                    convert_associated_const(ccx, ImplContainer(DefId::local(it.id)),
+                    convert_associated_const(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
                                              impl_item.name, impl_item.id,
                                              impl_item.vis.inherit_from(parent_visibility),
                                              ty, true /* has_value */);
@@ -860,7 +861,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
 
-                    convert_associated_type(ccx, ImplContainer(DefId::local(it.id)),
+                    convert_associated_type(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
                                             impl_item.name, impl_item.id, impl_item.vis,
                                             Some(typ));
                 }
@@ -879,7 +880,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                 }
             });
             convert_methods(ccx,
-                            ImplContainer(DefId::local(it.id)),
+                            ImplContainer(ccx.tcx.map.local_def_id(it.id)),
                             methods,
                             selfty,
                             &ty_generics,
@@ -899,15 +900,15 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             enforce_impl_params_are_constrained(tcx,
                                                 generics,
-                                                DefId::local(it.id),
+                                                ccx.tcx.map.local_def_id(it.id),
                                                 impl_items);
         },
         hir::ItemTrait(_, _, _, ref trait_items) => {
             let trait_def = trait_def_of_item(ccx, it);
             let _: Result<(), ErrorReported> = // any error is already reported, can ignore
-                ccx.ensure_super_predicates(it.span, DefId::local(it.id));
+                ccx.ensure_super_predicates(it.span, ccx.tcx.map.local_def_id(it.id));
             convert_trait_predicates(ccx, it);
-            let trait_predicates = tcx.lookup_predicates(DefId::local(it.id));
+            let trait_predicates = tcx.lookup_predicates(ccx.tcx.map.local_def_id(it.id));
 
             debug!("convert: trait_bounds={:?}", trait_predicates);
 
@@ -917,14 +918,18 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                     hir::ConstTraitItem(ref ty, ref default) => {
                         let ty = ccx.icx(&trait_predicates)
                                     .to_ty(&ExplicitRscope, ty);
-                        tcx.register_item_type(DefId::local(trait_item.id),
+                        tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
                                                TypeScheme {
                                                    generics: trait_def.generics.clone(),
                                                    ty: ty,
                                                });
-                        convert_associated_const(ccx, TraitContainer(DefId::local(it.id)),
-                                                 trait_item.name, trait_item.id,
-                                                 hir::Public, ty, default.is_some());
+                        convert_associated_const(ccx,
+                                                 TraitContainer(ccx.tcx.map.local_def_id(it.id)),
+                                                 trait_item.name,
+                                                 trait_item.id,
+                                                 hir::Public,
+                                                 ty,
+                                                 default.is_some())
                     }
                     _ => {}
                 }
@@ -938,8 +943,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                             |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
                         });
 
-                        convert_associated_type(ccx, TraitContainer(DefId::local(it.id)),
-                                                trait_item.name, trait_item.id, hir::Public,
+                        convert_associated_type(ccx,
+                                                TraitContainer(ccx.tcx.map.local_def_id(it.id)),
+                                                trait_item.name,
+                                                trait_item.id,
+                                                hir::Public,
                                                 typ);
                     }
                     _ => {}
@@ -956,7 +964,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             // Run convert_methods on the trait methods.
             convert_methods(ccx,
-                            TraitContainer(DefId::local(it.id)),
+                            TraitContainer(ccx.tcx.map.local_def_id(it.id)),
                             methods,
                             tcx.mk_self_type(),
                             &trait_def.generics,
@@ -964,7 +972,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             // Add an entry mapping
             let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
-                let def_id = DefId::local(trait_item.id);
+                let def_id = ccx.tcx.map.local_def_id(trait_item.id);
                 match trait_item.node {
                     hir::ConstTraitItem(..) => {
                         ty::ConstTraitItemId(def_id)
@@ -977,7 +985,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                     }
                 }
             }).collect());
-            tcx.trait_item_def_ids.borrow_mut().insert(DefId::local(it.id), trait_item_def_ids);
+            tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+                                                       trait_item_def_ids);
 
             // This must be done after `collect_trait_methods` so that
             // we have a method type stored for every method.
@@ -998,7 +1007,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             let (scheme, predicates) = convert_typed_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, scheme.ty);
 
-            let variant = tcx.lookup_adt_def_master(DefId::local(it.id)).struct_variant();
+            let it_def_id = ccx.tcx.map.local_def_id(it.id);
+            let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant();
 
             for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) {
                 convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
@@ -1036,14 +1046,14 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>,
                 .iter()
                 .map(|field| field.unsubst_ty())
                 .collect();
-            tcx.mk_ctor_fn(DefId::local(ctor_id),
+            tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id),
                            &inputs[..],
                            scheme.ty)
         }
     };
     write_ty_to_tcx(tcx, ctor_id, ctor_ty);
-    tcx.predicates.borrow_mut().insert(DefId::local(ctor_id), predicates);
-    tcx.register_item_type(DefId::local(ctor_id),
+    tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates);
+    tcx.register_item_type(tcx.map.local_def_id(ctor_id),
                            TypeScheme {
                                generics: scheme.generics,
                                ty: ctor_ty
@@ -1092,10 +1102,11 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>,
                                 did: DefId,
                                 name: ast::Name,
                                 disr_val: ty::Disr,
-                                def: &hir::StructDef) -> ty::VariantDefData<'tcx, 'tcx> {
+                                def: &hir::StructDef,
+                                ctor_id: DefId) -> ty::VariantDefData<'tcx, 'tcx> {
     let mut seen_fields: FnvHashMap<ast::Name, Span> = FnvHashMap();
     let fields = def.fields.iter().map(|f| {
-        let fid = DefId::local(f.node.id);
+        let fid = tcx.map.local_def_id(f.node.id);
         match f.node.kind {
             hir::NamedField(name, vis) => {
                 let dup_span = seen_fields.get(&name).cloned();
@@ -1119,7 +1130,8 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>,
         did: did,
         name: name,
         disr_val: disr_val,
-        fields: fields
+        fields: fields,
+        ctor_id: ctor_id
     }
 }
 
@@ -1129,11 +1141,13 @@ fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>,
                             -> ty::AdtDefMaster<'tcx>
 {
 
-    let did = DefId::local(it.id);
+    let did = tcx.map.local_def_id(it.id);
+    let ctor_id = def.ctor_id.map_or(did,
+        |ctor_id| tcx.map.local_def_id(ctor_id));
     tcx.intern_adt_def(
         did,
         ty::AdtKind::Struct,
-        vec![convert_struct_variant(tcx, did, it.name, 0, def)]
+        vec![convert_struct_variant(tcx, did, it.name, 0, def, ctor_id)]
     )
 }
 
@@ -1206,7 +1220,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>,
                                   disr: ty::Disr)
                                   -> ty::VariantDefData<'tcx, 'tcx>
     {
-        let did = DefId::local(v.node.id);
+        let did = tcx.map.local_def_id(v.node.id);
         let name = v.node.name;
         match v.node.kind {
             hir::TupleVariantKind(ref va) => {
@@ -1216,19 +1230,20 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>,
                     disr_val: disr,
                     fields: va.iter().map(|&hir::VariantArg { id, .. }| {
                         ty::FieldDefData::new(
-                            DefId::local(id),
+                            tcx.map.local_def_id(id),
                             special_idents::unnamed_field.name,
                             hir::Visibility::Public
                         )
-                    }).collect()
+                    }).collect(),
+                    ctor_id: did
                 }
             }
             hir::StructVariantKind(ref def) => {
-                convert_struct_variant(tcx, did, name, disr, &def)
+                convert_struct_variant(tcx, did, name, disr, &def, did)
             }
         }
     }
-    let did = DefId::local(it.id);
+    let did = tcx.map.local_def_id(it.id);
     let repr_hints = tcx.lookup_repr_hints(did);
     let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
     let mut prev_disr = None;
@@ -1242,7 +1257,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>,
         prev_disr = Some(disr);
         v
     }).collect();
-    tcx.intern_adt_def(DefId::local(it.id), ty::AdtKind::Enum, variants)
+    tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
 }
 
 /// Ensures that the super-predicates of the trait with def-id
@@ -1260,19 +1275,19 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
 
     debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
 
-    if trait_def_id.krate != LOCAL_CRATE {
+    let trait_node_id = if let Some(n) = tcx.map.as_local_node_id(trait_def_id) {
+        n
+    } else {
         // If this trait comes from an external crate, then all of the
         // supertraits it may depend on also must come from external
         // crates, and hence all of them already have their
         // super-predicates "converted" (and available from crate
         // meta-data), so there is no need to transitively test them.
         return Vec::new();
-    }
+    };
 
     let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
     let superpredicates = superpredicates.unwrap_or_else(|| {
-        let trait_node_id = trait_def_id.node;
-
         let item = match ccx.tcx.map.get(trait_node_id) {
             hir_map::NodeItem(item) => item,
             _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id))
@@ -1315,7 +1330,7 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt,
             predicates: VecPerParamSpace::new(superbounds, vec![], vec![])
         };
         debug!("superpredicates for trait {:?} = {:?}",
-               DefId::local(item.id),
+               tcx.map.local_def_id(item.id),
                superpredicates);
 
         tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
@@ -1338,7 +1353,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                it: &hir::Item)
                                -> &'tcx ty::TraitDef<'tcx>
 {
-    let def_id = DefId::local(it.id);
+    let def_id = ccx.tcx.map.local_def_id(it.id);
     let tcx = ccx.tcx;
 
     if let Some(def) = tcx.trait_defs.borrow().get(&def_id) {
@@ -1402,7 +1417,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     .iter()
                     .enumerate()
                     .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion {
-                        param_id: def.lifetime.id,
+                        def_id: tcx.map.local_def_id(def.lifetime.id),
                         space: TypeSpace,
                         index: i as u32,
                         name: def.lifetime.name
@@ -1452,7 +1467,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item)
     let tcx = ccx.tcx;
     let trait_def = trait_def_of_item(ccx, it);
 
-    let def_id = DefId::local(it.id);
+    let def_id = ccx.tcx.map.local_def_id(it.id);
 
     let (generics, items) = match it.node {
         hir::ItemTrait(_, ref generics, _, ref items) => (generics, items),
@@ -1526,23 +1541,23 @@ fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                   def_id: DefId)
                                   -> ty::TypeScheme<'tcx>
 {
-    if def_id.krate != LOCAL_CRATE {
-        return ccx.tcx.lookup_item_type(def_id);
-    }
-
-    match ccx.tcx.map.find(def_id.node) {
-        Some(hir_map::NodeItem(item)) => {
-            type_scheme_of_item(ccx, &*item)
-        }
-        Some(hir_map::NodeForeignItem(foreign_item)) => {
-            let abi = ccx.tcx.map.get_foreign_abi(def_id.node);
-            type_scheme_of_foreign_item(ccx, &*foreign_item, abi)
-        }
-        x => {
-            ccx.tcx.sess.bug(&format!("unexpected sort of node \
-                                            in get_item_type_scheme(): {:?}",
-                                       x));
+    if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) {
+        match ccx.tcx.map.find(node_id) {
+            Some(hir_map::NodeItem(item)) => {
+                type_scheme_of_item(ccx, &*item)
+            }
+            Some(hir_map::NodeForeignItem(foreign_item)) => {
+                let abi = ccx.tcx.map.get_foreign_abi(node_id);
+                type_scheme_of_foreign_item(ccx, &*foreign_item, abi)
+            }
+            x => {
+                ccx.tcx.sess.bug(&format!("unexpected sort of node \
+                                           in get_item_type_scheme(): {:?}",
+                                          x));
+            }
         }
+    } else {
+        ccx.tcx.lookup_item_type(def_id)
     }
 }
 
@@ -1551,7 +1566,7 @@ fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                 -> ty::TypeScheme<'tcx>
 {
     memoized(&ccx.tcx.tcache,
-             DefId::local(it.id),
+             ccx.tcx.map.local_def_id(it.id),
              |_| compute_type_scheme_of_item(ccx, it))
 }
 
@@ -1568,7 +1583,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
             let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
             let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl);
-            let ty = tcx.mk_fn(Some(DefId::local(it.id)), tcx.mk_bare_fn(tofd));
+            let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd));
             ty::TypeScheme { ty: ty, generics: ty_generics }
         }
         hir::ItemTy(ref t, ref generics) => {
@@ -1643,12 +1658,12 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     };
 
-    let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id),
+    let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
                                                              predicates.clone());
     assert!(prev_predicates.is_none());
 
     // Debugging aid.
-    if tcx.has_attr(DefId::local(it.id), "rustc_object_lifetime_default") {
+    if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") {
         let object_lifetime_default_reprs: String =
             scheme.generics.types.iter()
                                  .map(|t| match t.object_lifetime_default {
@@ -1671,7 +1686,7 @@ fn type_scheme_of_foreign_item<'a, 'tcx>(
     -> ty::TypeScheme<'tcx>
 {
     memoized(&ccx.tcx.tcache,
-             DefId::local(it.id),
+             ccx.tcx.map.local_def_id(it.id),
              |_| compute_type_scheme_of_foreign_item(ccx, it, abi))
 }
 
@@ -1716,7 +1731,8 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     };
 
-    let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id), predicates);
+    let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+                                                             predicates);
     assert!(prev_predicates.is_none());
 }
 
@@ -1740,7 +1756,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                    -> ty::Generics<'tcx>
 {
     debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})",
-           DefId::local(trait_id), substs);
+           ccx.tcx.map.local_def_id(trait_id), substs);
 
     let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics);
 
@@ -1756,8 +1772,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         space: SelfSpace,
         index: 0,
         name: special_idents::type_self.name,
-        def_id: DefId::local(param_id),
-        default_def_id: DefId::local(parent),
+        def_id: ccx.tcx.map.local_def_id(param_id),
+        default_def_id: ccx.tcx.map.local_def_id(parent),
         default: None,
         object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
     };
@@ -1876,9 +1892,10 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
     for (index, param) in early_lifetimes.iter().enumerate() {
         let index = index as u32;
+        let def_id = tcx.map.local_def_id(param.lifetime.id);
         let region =
             ty::ReEarlyBound(ty::EarlyBoundRegion {
-                param_id: param.lifetime.id,
+                def_id: def_id,
                 space: space,
                 index: index,
                 name: param.lifetime.name
@@ -1964,7 +1981,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         let def = ty::RegionParameterDef { name: l.lifetime.name,
                                            space: space,
                                            index: i as u32,
-                                           def_id: DefId::local(l.lifetime.id),
+                                           def_id: ccx.tcx.map.local_def_id(l.lifetime.id),
                                            bounds: bounds };
         result.regions.push(space, def);
     }
@@ -2032,8 +2049,8 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         space: space,
         index: index,
         name: param.name,
-        def_id: DefId::local(param.id),
-        default_def_id: DefId::local(parent),
+        def_id: ccx.tcx.map.local_def_id(param.id),
+        default_def_id: ccx.tcx.map.local_def_id(parent),
         default: default,
         object_lifetime_default: object_lifetime_default,
     };
@@ -2376,9 +2393,10 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
         tcx.fold_regions(value, &mut false, |region, _| {
             match region {
                 ty::ReEarlyBound(data) => {
-                    let def_id = DefId::local(data.param_id);
-                    ty::ReFree(ty::FreeRegion { scope: scope,
-                                                bound_region: ty::BrNamed(def_id, data.name) })
+                    ty::ReFree(ty::FreeRegion {
+                        scope: scope,
+                        bound_region: ty::BrNamed(data.def_id, data.name)
+                    })
                 }
                 _ => region
             }
@@ -2423,7 +2441,7 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     let lifetimes_in_associated_types: HashSet<_> =
         impl_items.iter()
-                  .map(|item| tcx.impl_or_trait_item(DefId::local(item.id)))
+                  .map(|item| tcx.impl_or_trait_item(tcx.map.local_def_id(item.id)))
                   .filter_map(|item| match item {
                       ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
                       ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
@@ -2436,7 +2454,8 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
                   .collect();
 
     for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() {
-        let region = ty::EarlyBoundRegion { param_id: lifetime_def.lifetime.id,
+        let def_id = tcx.map.local_def_id(lifetime_def.lifetime.id);
+        let region = ty::EarlyBoundRegion { def_id: def_id,
                                             space: TypeSpace,
                                             index: index as u32,
                                             name: lifetime_def.lifetime.name };
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a11cd54b658..7156c9c6091 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -98,20 +98,20 @@ extern crate rustc;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_front;
 
+pub use rustc::front;
 pub use rustc::lint;
 pub use rustc::metadata;
 pub use rustc::middle;
 pub use rustc::session;
 pub use rustc::util;
 
+use front::map as hir_map;
 use middle::def;
-use middle::def_id::DefId;
 use middle::infer;
 use middle::subst;
 use middle::ty::{self, Ty, HasTypeFlags};
 use session::config;
 use util::common::time;
-use rustc::front::map as hir_map;
 use rustc_front::hir;
 
 use syntax::codemap::Span;
@@ -239,7 +239,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 }
                 _ => ()
             }
-            let se_ty = tcx.mk_fn(Some(DefId::local(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
+            let main_def_id = tcx.map.local_def_id(main_id);
+            let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -285,7 +286,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
 
-            let se_ty = tcx.mk_fn(Some(DefId::local(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
+            let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
+                                  tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: abi::Rust,
                 sig: ty::Binder(ty::FnSig {
diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs
index 229c52a4e5e..8152e685d8d 100644
--- a/src/librustc_typeck/variance.rs
+++ b/src/librustc_typeck/variance.rs
@@ -266,7 +266,7 @@ use self::ParamKind::*;
 
 use arena;
 use arena::TypedArena;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
 use middle::resolve_lifetime as rl;
 use middle::subst;
 use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace};
@@ -403,10 +403,10 @@ fn lang_items(tcx: &ty::ctxt) -> Vec<(ast::NodeId,Vec<ty::Variance>)> {
 
         ];
 
-    all.into_iter()
+    all.into_iter() // iterating over (Option<DefId>, Variance)
        .filter(|&(ref d,_)| d.is_some())
-       .filter(|&(ref d,_)| d.as_ref().unwrap().is_local())
-       .map(|(d, v)| (d.unwrap().node, v))
+       .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance)
+       .filter_map(|(d, v)| tcx.map.as_local_node_id(d).map(|n| (n, v))) // (NodeId, Variance)
        .collect()
 }
 
@@ -451,9 +451,10 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
         // "invalid item id" from "item id with no
         // parameters".
         if self.num_inferred() == inferreds_on_entry {
+            let item_def_id = self.tcx.map.local_def_id(item_id);
             let newly_added =
                 self.tcx.item_variance_map.borrow_mut().insert(
-                    DefId::local(item_id),
+                    item_def_id,
                     self.empty_variances.clone()).is_none();
             assert!(newly_added);
         }
@@ -486,7 +487,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
                 param_id={}, \
                 inf_index={:?}, \
                 initial_variance={:?})",
-               self.tcx.item_path_str(DefId::local(item_id)),
+               self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)),
                item_id, kind, space, index, param_id, inf_index,
                initial_variance);
     }
@@ -596,8 +597,8 @@ fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>,
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
-        let did = DefId::local(item.id);
         let tcx = self.terms_cx.tcx;
+        let did = tcx.map.local_def_id(item.id);
 
         debug!("visit_item item={}", tcx.map.node_to_string(item.id));
 
@@ -739,11 +740,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                          -> VarianceTermPtr<'a> {
         assert_eq!(param_def_id.krate, item_def_id.krate);
 
-        if param_def_id.is_local() {
+        if let Some(param_node_id) = self.tcx().map.as_local_node_id(param_def_id) {
             // Parameter on an item defined within current crate:
             // variance not yet inferred, so return a symbolic
             // variance.
-            let InferredIndex(index) = self.inferred_index(param_def_id.node);
+            let InferredIndex(index) = self.inferred_index(param_node_id);
             self.terms_cx.inferred_infos[index].term
         } else {
             // Parameter on an item defined within another crate:
@@ -922,8 +923,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
             ty::TyParam(ref data) => {
                 let def_id = generics.types.get(data.space, data.idx as usize).def_id;
-                assert_eq!(def_id.krate, LOCAL_CRATE);
-                match self.terms_cx.inferred_map.get(&def_id.node) {
+                let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
+                match self.terms_cx.inferred_map.get(&node_id) {
                     Some(&index) => {
                         self.add_constraint(index, variance);
                     }
@@ -1011,8 +1012,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                    variance: VarianceTermPtr<'a>) {
         match region {
             ty::ReEarlyBound(ref data) => {
-                if self.is_to_be_inferred(data.param_id) {
-                    let index = self.inferred_index(data.param_id);
+                let node_id = self.tcx().map.as_local_node_id(data.def_id).unwrap();
+                if self.is_to_be_inferred(node_id) {
+                    let index = self.inferred_index(node_id);
                     self.add_constraint(index, variance);
                 }
             }
@@ -1163,7 +1165,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
                     item_id,
                     item_variances);
 
-            let item_def_id = DefId::local(item_id);
+            let item_def_id = tcx.map.local_def_id(item_id);
 
             // For unit testing: check for a special "rustc_variance"
             // attribute and report an error with various results if found.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 89020b011a9..3492635a20b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -39,7 +39,7 @@ use rustc::metadata::cstore;
 use rustc::metadata::csearch;
 use rustc::metadata::decoder;
 use rustc::middle::def;
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::middle::def_id::{DefId, DefIndex};
 use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
 use rustc::middle::ty;
 use rustc::middle::stability;
@@ -188,7 +188,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
                     attrs: child.attrs.clone(),
                     visibility: Some(hir::Public),
                     stability: None,
-                    def_id: DefId::local(prim.to_node_id()),
+                    def_id: DefId::local(prim.to_def_index()),
                     inner: PrimitiveItem(prim),
                 });
             }
@@ -419,7 +419,7 @@ impl Clean<Item> for doctree::Module {
             source: whence.clean(cx),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             inner: ModuleItem(Module {
                is_crate: self.is_crate,
                items: items
@@ -495,7 +495,7 @@ impl Clean<TyParam> for hir::TyParam {
     fn clean(&self, cx: &DocContext) -> TyParam {
         TyParam {
             name: self.name.clean(cx),
-            did: DefId { krate: LOCAL_CRATE, node: self.id },
+            did: cx.map.local_def_id(self.id),
             bounds: self.bounds.clean(cx),
             default: self.default.clean(cx),
         }
@@ -1087,7 +1087,7 @@ impl Clean<Item> for doctree::Function {
             source: self.whence.clean(cx),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             inner: FunctionItem(Function {
                 decl: self.decl.clean(cx),
                 generics: self.generics.clean(cx),
@@ -1137,10 +1137,10 @@ impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
 impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
-        let mut names = if did.node != 0 {
-            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
+        let mut names = if let Some(_) = cx.map.as_local_node_id(did) {
+            vec![].into_iter()
         } else {
-            Vec::new().into_iter()
+            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
         }.peekable();
         if names.peek().map(|s| &**s) == Some("self") {
             let _ = names.next();
@@ -1210,7 +1210,7 @@ impl Clean<Item> for doctree::Trait {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: TraitItem(Trait {
@@ -1260,9 +1260,9 @@ impl Clean<Item> for hir::TraitItem {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: None,
-            stability: get_stability(cx, DefId::local(self.id)),
+            stability: get_stability(cx, cx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1293,9 +1293,9 @@ impl Clean<Item> for hir::ImplItem {
             name: Some(self.name.clean(cx)),
             source: self.span.clean(cx),
             attrs: self.attrs.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
-            stability: get_stability(cx, DefId::local(self.id)),
+            stability: get_stability(cx, cx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1559,8 +1559,9 @@ impl PrimitiveType {
     /// Creates a rustdoc-specific node id for primitive types.
     ///
     /// These node ids are generally never used by the AST itself.
-    pub fn to_node_id(&self) -> ast::NodeId {
-        u32::MAX - 1 - (*self as u32)
+    pub fn to_def_index(&self) -> DefIndex {
+        let x = u32::MAX - 1 - (*self as u32);
+        DefIndex::new(x as usize)
     }
 }
 
@@ -1659,7 +1660,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                     type_params: Vec::new(),
                     where_predicates: Vec::new()
                 },
-                decl: (DefId::local(0), &fty.sig).clean(cx),
+                decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
                 abi: fty.abi.to_string(),
             }),
             ty::TyStruct(def, substs) |
@@ -1727,8 +1728,8 @@ impl Clean<Item> for hir::StructField {
             attrs: self.node.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Some(vis),
-            stability: get_stability(cx, DefId::local(self.node.id)),
-            def_id: DefId::local(self.node.id),
+            stability: get_stability(cx, cx.map.local_def_id(self.node.id)),
+            def_id: cx.map.local_def_id(self.node.id),
             inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
         }
     }
@@ -1744,7 +1745,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
         let (name, attrs) = if self.name == unnamed_field.name {
             (None, None)
         } else {
-            (Some(self.name), Some(attr_map.get(&self.did.node).unwrap()))
+            (Some(self.name), Some(attr_map.get(&self.did).unwrap()))
         };
 
         Item {
@@ -1781,7 +1782,7 @@ impl Clean<Item> for doctree::Struct {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: StructItem(Struct {
@@ -1827,7 +1828,7 @@ impl Clean<Item> for doctree::Enum {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: EnumItem(Enum {
@@ -1852,7 +1853,7 @@ impl Clean<Item> for doctree::Variant {
             source: self.whence.clean(cx),
             visibility: None,
             stability: self.stab.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             inner: VariantItem(Variant {
                 kind: self.kind.clean(cx),
             }),
@@ -2082,7 +2083,7 @@ impl Clean<Item> for doctree::Typedef {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id.clone()),
+            def_id: cx.map.local_def_id(self.id.clone()),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: TypedefItem(Typedef {
@@ -2133,7 +2134,7 @@ impl Clean<Item> for doctree::Static {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: StaticItem(Static {
@@ -2157,7 +2158,7 @@ impl Clean<Item> for doctree::Constant {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: ConstantItem(Constant {
@@ -2231,7 +2232,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: ImplItem(Impl {
@@ -2313,7 +2314,7 @@ impl Clean<Item> for doctree::DefaultImpl {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: Some(hir::Public),
             stability: None,
             inner: DefaultImplItem(DefaultImpl {
@@ -2330,7 +2331,7 @@ impl Clean<Item> for doctree::ExternCrate {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(0),
+            def_id: cx.map.local_def_id(0),
             visibility: self.vis.clean(cx),
             stability: None,
             inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
@@ -2395,7 +2396,7 @@ impl Clean<Vec<Item>> for doctree::Import {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: DefId::local(0),
+            def_id: cx.map.local_def_id(0),
             visibility: self.vis.clean(cx),
             stability: None,
             inner: ImportItem(inner)
@@ -2481,9 +2482,9 @@ impl Clean<Item> for hir::ForeignItem {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
-            stability: get_stability(cx, DefId::local(self.id)),
+            stability: get_stability(cx, cx.map.local_def_id(self.id)),
             inner: inner,
         }
     }
@@ -2570,17 +2571,19 @@ fn name_from_pat(p: &hir::Pat) -> String {
 fn resolve_type(cx: &DocContext,
                 path: Path,
                 id: ast::NodeId) -> Type {
+    debug!("resolve_type({:?},{:?})", path, id);
     let tcx = match cx.tcx_opt() {
         Some(tcx) => tcx,
         // If we're extracting tests, this return value doesn't matter.
         None => return Primitive(Bool),
     };
-    debug!("searching for {} in defmap", id);
     let def = match tcx.def_map.borrow().get(&id) {
         Some(k) => k.full_def(),
         None => panic!("unresolved id not in defmap")
     };
 
+    debug!("resolve_type: def={:?}", def);
+
     let is_generic = match def {
         def::DefPrimTy(p) => match p {
             hir::TyStr => return Primitive(Str),
@@ -2610,6 +2613,8 @@ fn resolve_type(cx: &DocContext,
 }
 
 fn register_def(cx: &DocContext, def: def::Def) -> DefId {
+    debug!("register_def({:?})", def);
+
     let (did, kind) = match def {
         def::DefFn(i, _) => (i, TypeFunction),
         def::DefTy(i, false) => (i, TypeTypedef),
@@ -2619,6 +2624,8 @@ fn register_def(cx: &DocContext, def: def::Def) -> DefId {
         def::DefMod(i) => (i, TypeModule),
         def::DefStatic(i, _) => (i, TypeStatic),
         def::DefVariant(i, _, _) => (i, TypeEnum),
+        def::DefSelfTy(Some(def_id), _) => (def_id, TypeTrait),
+        def::DefSelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
         _ => return def.def_id()
     };
     if did.is_local() { return did }
@@ -2661,7 +2668,7 @@ impl Clean<Item> for doctree::Macro {
             source: self.whence.clean(cx),
             visibility: hir::Public.clean(cx),
             stability: self.stab.clean(cx),
-            def_id: DefId::local(self.id),
+            def_id: cx.map.local_def_id(self.id),
             inner: MacroItem(Macro {
                 source: self.whence.to_src(cx),
                 imported_from: self.imported_from.clean(cx),
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index d7238c827ab..c84a7e7c560 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -13,13 +13,13 @@ use rustc_lint;
 use rustc_driver::{driver, target_features};
 use rustc::session::{self, config};
 use rustc::middle::def_id::DefId;
-use rustc::middle::{privacy, ty};
+use rustc::middle::ty;
 use rustc::front::map as hir_map;
 use rustc::lint;
+use rustc::util::nodemap::DefIdSet;
 use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_front::lowering::lower_crate;
-use rustc_front::hir;
 
 use syntax::{ast, codemap, diagnostic};
 use syntax::feature_gate::UnstableFeatures;
@@ -44,7 +44,7 @@ pub type ExternalPaths = RefCell<Option<HashMap<DefId,
                                                 (Vec<String>, clean::TypeKind)>>>;
 
 pub struct DocContext<'a, 'tcx: 'a> {
-    pub krate: &'tcx hir::Crate,
+    pub map: &'a hir_map::Map<'tcx>,
     pub maybe_typed: MaybeTyped<'a, 'tcx>,
     pub input: Input,
     pub external_paths: ExternalPaths,
@@ -77,8 +77,8 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> {
 }
 
 pub struct CrateAnalysis {
-    pub exported_items: privacy::ExportedItems,
-    pub public_items: privacy::PublicItems,
+    pub exported_items: DefIdSet,
+    pub public_items: DefIdSet,
     pub external_paths: ExternalPaths,
     pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
     pub inlined: RefCell<Option<HashSet<DefId>>>,
@@ -147,8 +147,19 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
                                         |tcx, analysis| {
         let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
 
+        // Convert from a NodeId set to a DefId set since we don't always have easy access
+        // to the map from defid -> nodeid
+        let exported_items: DefIdSet =
+            exported_items.into_iter()
+                          .map(|n| tcx.map.local_def_id(n))
+                          .collect();
+        let public_items: DefIdSet =
+            public_items.into_iter()
+                        .map(|n| tcx.map.local_def_id(n))
+                        .collect();
+
         let ctxt = DocContext {
-            krate: tcx.map.krate(),
+            map: &tcx.map,
             maybe_typed: Typed(tcx),
             input: input,
             external_traits: RefCell::new(Some(HashMap::new())),
@@ -158,7 +169,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
             populated_crate_impls: RefCell::new(HashSet::new()),
             deref_trait_did: Cell::new(None),
         };
-        debug!("crate: {:?}", ctxt.krate);
+        debug!("crate: {:?}", ctxt.map.krate());
 
         let mut analysis = CrateAnalysis {
             exported_items: exported_items,
@@ -171,7 +182,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
 
         let krate = {
             let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
-            v.visit(ctxt.krate);
+            v.visit(ctxt.map.krate());
             v.clean(&ctxt)
         };
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 947ae3abd8d..d12c5d2c6fb 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,9 +18,9 @@
 use std::fmt;
 use std::iter::repeat;
 
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::metadata::cstore::LOCAL_CRATE;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
 use syntax::abi::Abi;
-use syntax::ast;
 use rustc_front::hir;
 
 use clean;
@@ -386,7 +386,7 @@ fn primitive_link(f: &mut fmt::Formatter,
         Some(&cnum) => {
             let path = &m.paths[&DefId {
                 krate: cnum,
-                node: ast::CRATE_NODE_ID,
+                index: CRATE_DEF_INDEX,
             }];
             let loc = match m.extern_locations[&cnum] {
                 (_, render::Remote(ref s)) => Some(s.to_string()),
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index b34f1a01a2b..cf03482e18b 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -53,8 +53,9 @@ use externalfiles::ExternalHtml;
 
 use serialize::json::{self, ToJson};
 use syntax::{abi, ast, attr};
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
-use rustc::util::nodemap::NodeSet;
+use rustc::metadata::cstore::LOCAL_CRATE;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::util::nodemap::DefIdSet;
 use rustc_front::hir;
 
 use clean::{self, SelfTy};
@@ -205,7 +206,7 @@ pub struct Cache {
     search_index: Vec<IndexItem>,
     privmod: bool,
     remove_priv: bool,
-    public_items: NodeSet,
+    public_items: DefIdSet,
     deref_trait_did: Option<DefId>,
 
     // In rare case where a structure is defined in one module but implemented
@@ -213,7 +214,7 @@ pub struct Cache {
     // then the fully qualified name of the structure isn't presented in `paths`
     // yet when its implementation methods are being indexed. Caches such methods
     // and their parent id here and indexes them at the end of crate parsing.
-    orphan_methods: Vec<(ast::NodeId, clean::Item)>,
+    orphan_methods: Vec<(DefId, clean::Item)>,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -377,7 +378,7 @@ pub fn run(mut krate: clean::Crate,
     let analysis = ::ANALYSISKEY.with(|a| a.clone());
     let analysis = analysis.borrow();
     let public_items = analysis.as_ref().map(|a| a.public_items.clone());
-    let public_items = public_items.unwrap_or(NodeSet());
+    let public_items = public_items.unwrap_or(DefIdSet());
     let paths: HashMap<DefId, (Vec<String>, ItemType)> =
       analysis.as_ref().map(|a| {
         let paths = a.external_paths.borrow_mut().take().unwrap();
@@ -412,7 +413,7 @@ pub fn run(mut krate: clean::Crate,
     for &(n, ref e) in &krate.externs {
         cache.extern_locations.insert(n, (e.name.clone(),
                                           extern_location(e, &cx.dst)));
-        let did = DefId { krate: n, node: ast::CRATE_NODE_ID };
+        let did = DefId { krate: n, index: CRATE_DEF_INDEX };
         cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
     }
 
@@ -459,8 +460,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
 
         // Attach all orphan methods to the type's definition if the type
         // has since been learned.
-        for &(pid, ref item) in orphan_methods {
-            let did = DefId::local(pid);
+        for &(did, ref item) in orphan_methods {
             match paths.get(&did) {
                 Some(&(ref fqp, _)) => {
                     // Needed to determine `self` type.
@@ -968,7 +968,7 @@ impl DocFolder for Cache {
                     if parent.is_local() {
                         // We have a parent, but we don't know where they're
                         // defined yet. Wait for later to index this item.
-                        self.orphan_methods.push((parent.node, item.clone()))
+                        self.orphan_methods.push((parent, item.clone()))
                     }
                 }
                 _ => {}
@@ -994,10 +994,11 @@ impl DocFolder for Cache {
                 // `public_items` map, so we can skip inserting into the
                 // paths map if there was already an entry present and we're
                 // not a public item.
-                let id = item.def_id.node;
-                if !self.paths.contains_key(&item.def_id) ||
-                   !item.def_id.is_local() ||
-                   self.public_items.contains(&id) {
+                if
+                    !self.paths.contains_key(&item.def_id) ||
+                    !item.def_id.is_local() ||
+                    self.public_items.contains(&item.def_id)
+                {
                     self.paths.insert(item.def_id,
                                       (self.stack.clone(), shortty(&item)));
                 }
@@ -1033,7 +1034,7 @@ impl DocFolder for Cache {
                     ref t => {
                         match t.primitive_type() {
                             Some(prim) => {
-                                let did = DefId::local(prim.to_node_id());
+                                let did = DefId::local(prim.to_def_index());
                                 self.parent_stack.push(did);
                                 true
                             }
@@ -1078,8 +1079,8 @@ impl DocFolder for Cache {
                             ref t => {
                                 t.primitive_type().and_then(|t| {
                                     self.primitive_locations.get(&t).map(|n| {
-                                        let id = t.to_node_id();
-                                        DefId { krate: *n, node: id }
+                                        let id = t.to_def_index();
+                                        DefId { krate: *n, index: id }
                                     })
                                 })
                             }
@@ -1420,7 +1421,7 @@ impl<'a> Item<'a> {
                          root = root,
                          path = path[..path.len() - 1].join("/"),
                          file = item_path(self.item),
-                         goto = self.item.def_id.node))
+                         goto = self.item.def_id.index.as_usize()))
         }
     }
 }
@@ -1480,7 +1481,7 @@ impl<'a> fmt::Display for Item<'a> {
                 Some(l) => {
                     try!(write!(fmt, "<a id='src-{}' class='srclink' \
                                        href='{}' title='{}'>[src]</a>",
-                                self.item.def_id.node, l, "goto source code"));
+                                self.item.def_id.index.as_usize(), l, "goto source code"));
                 }
                 None => {}
             }
@@ -2336,7 +2337,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f
         _ => {
             if let Some(prim) = target.primitive_type() {
                 if let Some(c) = cache().primitive_locations.get(&prim) {
-                    let did = DefId { krate: *c, node: prim.to_node_id() };
+                    let did = DefId { krate: *c, index: prim.to_def_index() };
                     try!(render_assoc_items(w, cx, did, what));
                 }
             }
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 8a57a50bdea..e7e38220825 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -8,12 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::collections::HashSet;
-use rustc::util::nodemap::NodeSet;
+use rustc::util::nodemap::DefIdSet;
 use std::cmp;
 use std::string::String;
 use std::usize;
-use syntax::ast;
 use rustc_front::hir;
 
 use clean;
@@ -24,18 +22,18 @@ use fold::DocFolder;
 
 /// Strip items marked `#[doc(hidden)]`
 pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
-    let mut stripped = HashSet::new();
+    let mut stripped = DefIdSet();
 
     // strip all #[doc(hidden)] items
     let krate = {
         struct Stripper<'a> {
-            stripped: &'a mut HashSet<ast::NodeId>
+            stripped: &'a mut DefIdSet
         };
         impl<'a> fold::DocFolder for Stripper<'a> {
             fn fold_item(&mut self, i: Item) -> Option<Item> {
                 if i.is_hidden_from_doc() {
                     debug!("found one in strip_hidden; removing");
-                    self.stripped.insert(i.def_id.node);
+                    self.stripped.insert(i.def_id);
 
                     // use a dedicated hidden item for given item type if any
                     match i.inner {
@@ -61,7 +59,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
     // strip any traits implemented on stripped items
     let krate = {
         struct ImplStripper<'a> {
-            stripped: &'a mut HashSet<ast::NodeId>
+            stripped: &'a mut DefIdSet
         };
         impl<'a> fold::DocFolder for ImplStripper<'a> {
             fn fold_item(&mut self, i: Item) -> Option<Item> {
@@ -70,12 +68,12 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
                            ref trait_, ..
                 }) = i.inner {
                     // Impls for stripped types don't need to exist
-                    if self.stripped.contains(&did.node) {
+                    if self.stripped.contains(&did) {
                         return None;
                     }
                     // Impls of stripped traits also don't need to exist
                     if let Some(clean::ResolvedPath { did, .. }) = *trait_ {
-                        if self.stripped.contains(&did.node) {
+                        if self.stripped.contains(&did) {
                             return None;
                         }
                     }
@@ -94,7 +92,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
 /// crate, specified by the `xcrate` flag.
 pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
     // This stripper collects all *retained* nodes.
-    let mut retained = HashSet::new();
+    let mut retained = DefIdSet();
     let analysis = super::ANALYSISKEY.with(|a| a.clone());
     let analysis = analysis.borrow();
     let analysis = analysis.as_ref().unwrap();
@@ -118,8 +116,8 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
 }
 
 struct Stripper<'a> {
-    retained: &'a mut HashSet<ast::NodeId>,
-    exported_items: &'a NodeSet,
+    retained: &'a mut DefIdSet,
+    exported_items: &'a DefIdSet,
 }
 
 impl<'a> fold::DocFolder for Stripper<'a> {
@@ -132,7 +130,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             clean::VariantItem(..) | clean::MethodItem(..) |
             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
                 if i.def_id.is_local() {
-                    if !self.exported_items.contains(&i.def_id.node) {
+                    if !self.exported_items.contains(&i.def_id) {
                         return None;
                     }
                     // Traits are in exported_items even when they're totally private.
@@ -143,8 +141,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             }
 
             clean::ConstantItem(..) => {
-                if i.def_id.is_local() &&
-                   !self.exported_items.contains(&i.def_id.node) {
+                if i.def_id.is_local() && !self.exported_items.contains(&i.def_id) {
                     return None;
                 }
             }
@@ -171,8 +168,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             clean::ImplItem(clean::Impl{
                 for_: clean::ResolvedPath{ did, .. }, ..
             }) => {
-                if did.is_local() &&
-                   !self.exported_items.contains(&did.node) {
+                if did.is_local() && !self.exported_items.contains(&did) {
                     return None;
                 }
             }
@@ -205,7 +201,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
         };
 
         let i = if fastreturn {
-            self.retained.insert(i.def_id.node);
+            self.retained.insert(i.def_id);
             return Some(i);
         } else {
             self.fold_item_recur(i)
@@ -220,7 +216,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                            i.doc_value().is_none() => None,
                     clean::ImplItem(ref i) if i.items.is_empty() => None,
                     _ => {
-                        self.retained.insert(i.def_id.node);
+                        self.retained.insert(i.def_id);
                         Some(i)
                     }
                 }
@@ -231,14 +227,13 @@ impl<'a> fold::DocFolder for Stripper<'a> {
 }
 
 // This stripper discards all private impls of traits
-struct ImplStripper<'a>(&'a HashSet<ast::NodeId>);
+struct ImplStripper<'a>(&'a DefIdSet);
 impl<'a> fold::DocFolder for ImplStripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if let clean::ImplItem(ref imp) = i.inner {
             match imp.trait_ {
                 Some(clean::ResolvedPath{ did, .. }) => {
-                    let ImplStripper(s) = *self;
-                    if did.is_local() && !s.contains(&did.node) {
+                    if did.is_local() && !self.0.contains(&did) {
                         return None;
                     }
                 }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 2f47353fee7..387e1a8cc07 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -22,6 +22,7 @@ use std::sync::{Arc, Mutex};
 
 use testing;
 use rustc_lint;
+use rustc::front::map as hir_map;
 use rustc::session::{self, config};
 use rustc::session::config::get_unstable_features_setting;
 use rustc::session::search_paths::{SearchPaths, PathKind};
@@ -86,8 +87,11 @@ pub fn run(input: &str,
 
     let opts = scrape_test_config(&krate);
 
+    let mut forest = hir_map::Forest::new(krate);
+    let map = hir_map::map_crate(&mut forest);
+
     let ctx = core::DocContext {
-        krate: &krate,
+        map: &map,
         maybe_typed: core::NotTyped(sess),
         input: input,
         external_paths: RefCell::new(Some(HashMap::new())),
@@ -99,7 +103,7 @@ pub fn run(input: &str,
     };
 
     let mut v = RustdocVisitor::new(&ctx, None);
-    v.visit(ctx.krate);
+    v.visit(ctx.map.krate());
     let mut krate = v.clean(&ctx);
     match crate_name {
         Some(name) => krate.name = name,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index d8181155677..264656835a3 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -21,7 +21,6 @@ use syntax::attr::AttrMetaMethods;
 use syntax::codemap::Span;
 
 use rustc::front::map as hir_map;
-use rustc::middle::def_id::DefId;
 use rustc::middle::stability;
 
 use rustc_front::hir;
@@ -63,8 +62,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     }
 
     fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
-        self.cx.tcx_opt().and_then(
-            |tcx| stability::lookup(tcx, DefId::local(id)).map(|x| x.clone()))
+        self.cx.tcx_opt().and_then(|tcx| {
+            self.cx.map.opt_local_def_id(id)
+                       .and_then(|def_id| stability::lookup(tcx, def_id))
+                       .cloned()
+        })
     }
 
     pub fn visit(&mut self, krate: &hir::Crate) {
@@ -206,16 +208,18 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             None => return false
         };
         let def = tcx.def_map.borrow()[&id].def_id();
-        if !def.is_local() { return false }
+        let def_node_id = match tcx.map.as_local_node_id(def) {
+            Some(n) => n, None => return false
+        };
         let analysis = match self.analysis {
             Some(analysis) => analysis, None => return false
         };
-        if !please_inline && analysis.public_items.contains(&def.node) {
+        if !please_inline && analysis.public_items.contains(&def) {
             return false
         }
-        if !self.view_item_stack.insert(def.node) { return false }
+        if !self.view_item_stack.insert(def_node_id) { return false }
 
-        let ret = match tcx.map.get(def.node) {
+        let ret = match tcx.map.get(def_node_id) {
             hir_map::NodeItem(it) => {
                 if glob {
                     let prev = mem::replace(&mut self.inlining_from_glob, true);
@@ -236,7 +240,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
             _ => false,
         };
-        self.view_item_stack.remove(&id);
+        self.view_item_stack.remove(&def_node_id);
         return ret;
     }
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 45e1d005863..d186918f44a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -167,13 +167,13 @@ impl fmt::Display for Ident {
 
 impl Encodable for Ident {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(&self.name.as_str())
+        self.name.encode(s)
     }
 }
 
 impl Decodable for Ident {
     fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
-        Ok(str_to_ident(&try!(d.read_str())[..]))
+        Ok(Ident::with_empty_ctxt(try!(Name::decode(d))))
     }
 }
 
diff --git a/src/test/compile-fail/borrowck-in-static.rs b/src/test/compile-fail/borrowck-in-static.rs
new file mode 100644
index 00000000000..16b0e8638de
--- /dev/null
+++ b/src/test/compile-fail/borrowck-in-static.rs
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that borrowck looks inside consts/statics
+
+static FN : &'static (Fn() -> (Box<Fn()->Box<i32>>) + Sync) = &|| {
+    let x = Box::new(0);
+    Box::new(|| x) //~ ERROR cannot move out of captured outer variable
+};
+
+fn main() {
+    let f = (FN)();
+    f();
+    f();
+}
diff --git a/src/test/compile-fail/issue-28113.rs b/src/test/compile-fail/issue-28113.rs
new file mode 100644
index 00000000000..c5c4fb07017
--- /dev/null
+++ b/src/test/compile-fail/issue-28113.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const X: u8 =
+    || -> u8 { 5 }() //~ ERROR function calls in constants are limited
+;
+
+fn main() {}
diff --git a/src/test/run-pass/issue-27890.rs b/src/test/run-pass/issue-27890.rs
new file mode 100644
index 00000000000..a33882a8331
--- /dev/null
+++ b/src/test/run-pass/issue-27890.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+static PLUS_ONE: &'static (Fn(i32) -> i32 + Sync) = (&|x: i32| { x + 1 })
+    as &'static (Fn(i32) -> i32 + Sync);
+
+fn main() {
+    assert_eq!(PLUS_ONE(2), 3);
+}