diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index e3df9d5d04be1..b32fa2cda8012 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -63,7 +63,7 @@ use crate::ty::subst::SubstsRef;
 use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::HirId;
 use rustc_span::symbol::Symbol;
 use std::fmt;
@@ -413,19 +413,19 @@ impl<'tcx> DepNodeParams<'tcx> for DefId {
     }
 }
 
-impl<'tcx> DepNodeParams<'tcx> for DefIndex {
+impl<'tcx> DepNodeParams<'tcx> for LocalDefId {
     const CAN_RECONSTRUCT_QUERY_KEY: bool = true;
 
     fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
-        tcx.hir().definitions().def_path_hash(*self).0
+        self.to_def_id().to_fingerprint(tcx)
     }
 
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
-        tcx.def_path_str(DefId::local(*self))
+        self.to_def_id().to_debug_str(tcx)
     }
 
     fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
-        dep_node.extract_def_id(tcx).map(|id| id.index)
+        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
     }
 }
 
@@ -477,7 +477,7 @@ impl<'tcx> DepNodeParams<'tcx> for HirId {
     fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
         let HirId { owner, local_id } = *self;
 
-        let def_path_hash = tcx.def_path_hash(DefId::local(owner));
+        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
         let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
 
         def_path_hash.0.combine(local_id)
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 97114b9e313f1..f60d20b8cb75d 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -902,7 +902,7 @@ impl DepGraph {
 
 fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    def_id.index == hir_id.owner
+    def_id.index == hir_id.owner.local_def_index
 }
 
 /// A "work product" is an intermediate result that we save into the
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 8b276d0a762c3..de0cc61118fed 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
-use rustc_hir::def_id::{DefIndex, LOCAL_CRATE};
+use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
@@ -30,12 +30,12 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// Source map
     source_map: &'a SourceMap,
 
-    map: IndexVec<DefIndex, HirOwnerData<'hir>>,
+    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
 
     /// The parent of this node
     parent_node: hir::HirId,
 
-    current_dep_node_owner: DefIndex,
+    current_dep_node_owner: LocalDefId,
 
     definitions: &'a definitions::Definitions,
 
@@ -98,7 +98,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         definitions: &'a definitions::Definitions,
         mut hcx: StableHashingContext<'a>,
     ) -> NodeCollector<'a, 'hir> {
-        let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX);
+        let root_mod_def_path_hash =
+            definitions.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX });
 
         let mut hir_body_nodes = Vec::new();
 
@@ -126,7 +127,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             krate,
             source_map: sess.source_map(),
             parent_node: hir::CRATE_HIR_ID,
-            current_dep_node_owner: CRATE_DEF_INDEX,
+            current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
             definitions,
             hcx,
             hir_body_nodes,
@@ -148,7 +149,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         crate_disambiguator: CrateDisambiguator,
         cstore: &dyn CrateStore,
         commandline_args_hash: u64,
-    ) -> (IndexVec<DefIndex, HirOwnerData<'hir>>, Svh) {
+    ) -> (IndexVec<LocalDefId, HirOwnerData<'hir>>, Svh) {
         // Insert bodies into the map
         for (id, body) in self.krate.bodies.iter() {
             let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
@@ -244,8 +245,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             assert_eq!(self.definitions.node_to_hir_id(node_id), hir_id);
 
             if hir_id.owner != self.current_dep_node_owner {
-                let node_str = match self.definitions.opt_def_index(node_id) {
-                    Some(def_index) => self.definitions.def_path(def_index).to_string_no_crate(),
+                let node_str = match self.definitions.opt_local_def_id(node_id) {
+                    Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(),
                     None => format!("{:?}", node),
                 };
 
@@ -285,7 +286,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         F: FnOnce(&mut Self, Fingerprint),
     >(
         &mut self,
-        dep_node_owner: DefIndex,
+        dep_node_owner: LocalDefId,
         item_like: &T,
         f: F,
     ) {
@@ -341,7 +342,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         debug!("visit_item: {:?}", i);
         debug_assert_eq!(
             i.hir_id.owner,
-            self.definitions.opt_def_index(self.definitions.hir_to_node_id(i.hir_id)).unwrap()
+            self.definitions.opt_local_def_id(self.definitions.hir_to_node_id(i.hir_id)).unwrap()
         );
         self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| {
             this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash);
@@ -373,7 +374,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         debug_assert_eq!(
             ti.hir_id.owner,
-            self.definitions.opt_def_index(self.definitions.hir_to_node_id(ti.hir_id)).unwrap()
+            self.definitions.opt_local_def_id(self.definitions.hir_to_node_id(ti.hir_id)).unwrap()
         );
         self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| {
             this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash);
@@ -387,7 +388,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
         debug_assert_eq!(
             ii.hir_id.owner,
-            self.definitions.opt_def_index(self.definitions.hir_to_node_id(ii.hir_id)).unwrap()
+            self.definitions.opt_local_def_id(self.definitions.hir_to_node_id(ii.hir_id)).unwrap()
         );
         self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| {
             this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash);
@@ -506,10 +507,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) {
-        let node_id = self.definitions.hir_to_node_id(macro_def.hir_id);
-        let def_index = self.definitions.opt_def_index(node_id).unwrap();
-
-        self.with_dep_node_owner(def_index, macro_def, |this, hash| {
+        self.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| {
             this.insert_with_hash(
                 macro_def.span,
                 macro_def.hir_id,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 42ccf7e72504b..aa4742ea891bb 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -5,11 +5,10 @@
 //! expressions) that are mostly just leftovers.
 
 use rustc_ast::ast;
-use rustc_ast::node_id::NodeMap;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_index::vec::IndexVec;
 use rustc_session::CrateDisambiguator;
 use rustc_span::hygiene::ExpnId;
@@ -78,25 +77,29 @@ impl DefPathTable {
 #[derive(Clone, Default)]
 pub struct Definitions {
     table: DefPathTable,
-    node_to_def_index: NodeMap<DefIndex>,
-    def_index_to_node: IndexVec<DefIndex, ast::NodeId>,
 
-    pub(super) node_to_hir_id: IndexVec<ast::NodeId, hir::HirId>,
-    /// The reverse mapping of `node_to_hir_id`.
-    pub(super) hir_to_node_id: FxHashMap<hir::HirId, ast::NodeId>,
+    def_id_to_span: IndexVec<LocalDefId, Span>,
+
+    // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId`
+    // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners.
+    node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+    def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+    pub(super) node_id_to_hir_id: IndexVec<ast::NodeId, hir::HirId>,
+    /// The reverse mapping of `node_id_to_hir_id`.
+    pub(super) hir_id_to_node_id: FxHashMap<hir::HirId, ast::NodeId>,
 
     /// If `ExpnId` is an ID of some macro expansion,
     /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
     parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
-    /// Item with a given `DefIndex` was defined during macro expansion with ID `ExpnId`.
-    expansions_that_defined: FxHashMap<DefIndex, ExpnId>,
-    next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
-    def_index_to_span: FxHashMap<DefIndex, Span>,
+    /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
+    expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
+    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
     /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
     /// we know what parent node that fragment should be attached to thanks to this table.
-    invocation_parents: FxHashMap<ExpnId, DefIndex>,
+    invocation_parents: FxHashMap<ExpnId, LocalDefId>,
     /// Indices of unnamed struct or variant fields with unresolved attributes.
-    placeholder_field_indices: NodeMap<usize>,
+    placeholder_field_indices: FxHashMap<ast::NodeId, usize>,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -296,13 +299,13 @@ impl Definitions {
         self.table.index_to_key.len()
     }
 
-    pub fn def_key(&self, index: DefIndex) -> DefKey {
-        self.table.def_key(index)
+    pub fn def_key(&self, id: LocalDefId) -> DefKey {
+        self.table.def_key(id.local_def_index)
     }
 
     #[inline(always)]
-    pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
-        self.table.def_path_hash(index)
+    pub fn def_path_hash(&self, id: LocalDefId) -> DefPathHash {
+        self.table.def_path_hash(id.local_def_index)
     }
 
     /// Returns the path from the crate root to `index`. The root
@@ -310,29 +313,27 @@ impl Definitions {
     /// 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 {
-        DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p))
+    pub fn def_path(&self, id: LocalDefId) -> DefPath {
+        DefPath::make(LOCAL_CRATE, id.local_def_index, |index| {
+            self.def_key(LocalDefId { local_def_index: index })
+        })
     }
 
     #[inline]
-    pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
-        self.node_to_def_index.get(&node).copied()
-    }
-
-    #[inline]
-    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
-        self.opt_def_index(node).map(DefId::local)
+    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<LocalDefId> {
+        self.node_id_to_def_id.get(&node).copied()
     }
 
+    // FIXME(eddyb) this function can and should return `LocalDefId`.
     #[inline]
     pub fn local_def_id(&self, node: ast::NodeId) -> DefId {
-        self.opt_local_def_id(node).unwrap()
+        self.opt_local_def_id(node).unwrap().to_def_id()
     }
 
     #[inline]
     pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
-        if def_id.krate == LOCAL_CRATE {
-            let node_id = self.def_index_to_node[def_id.index];
+        if let Some(def_id) = def_id.as_local() {
+            let node_id = self.def_id_to_node_id[def_id];
             if node_id != ast::DUMMY_NODE_ID {
                 return Some(node_id);
             }
@@ -342,39 +343,36 @@ impl Definitions {
 
     #[inline]
     pub fn as_local_hir_id(&self, def_id: DefId) -> Option<hir::HirId> {
-        if def_id.krate == LOCAL_CRATE {
-            let hir_id = self.def_index_to_hir_id(def_id.index);
+        if let Some(def_id) = def_id.as_local() {
+            let hir_id = self.local_def_id_to_hir_id(def_id);
             if hir_id != hir::DUMMY_HIR_ID { Some(hir_id) } else { None }
         } else {
             None
         }
     }
 
+    // FIXME(eddyb) rename to `hir_id_to_node_id`.
     #[inline]
     pub fn hir_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId {
-        self.hir_to_node_id[&hir_id]
+        self.hir_id_to_node_id[&hir_id]
     }
 
+    // FIXME(eddyb) rename to `node_id_to_hir_id`.
     #[inline]
     pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
-        self.node_to_hir_id[node_id]
+        self.node_id_to_hir_id[node_id]
     }
 
     #[inline]
-    pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId {
-        let node_id = self.def_index_to_node[def_index];
-        self.node_to_hir_id[node_id]
+    pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
+        let node_id = self.def_id_to_node_id[id];
+        self.node_id_to_hir_id[node_id]
     }
 
-    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists
-    /// and it's not `DUMMY_SP`.
+    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
-        if def_id.krate == LOCAL_CRATE {
-            self.def_index_to_span.get(&def_id.index).copied()
-        } else {
-            None
-        }
+        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
     }
 
     /// Adds a root definition (no parent) and a few other reserved definitions.
@@ -382,7 +380,7 @@ impl Definitions {
         &mut self,
         crate_name: &str,
         crate_disambiguator: CrateDisambiguator,
-    ) -> DefIndex {
+    ) -> LocalDefId {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -395,36 +393,38 @@ impl Definitions {
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
         // Create the definition.
-        let root_index = self.table.allocate(key, def_path_hash);
-        assert_eq!(root_index, CRATE_DEF_INDEX);
-        assert!(self.def_index_to_node.is_empty());
-        self.def_index_to_node.push(ast::CRATE_NODE_ID);
-        self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index);
-        self.set_invocation_parent(ExpnId::root(), root_index);
+        let root = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
+        assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
+
+        assert_eq!(self.def_id_to_node_id.push(ast::CRATE_NODE_ID), root);
+        assert_eq!(self.def_id_to_span.push(rustc_span::DUMMY_SP), root);
+
+        self.node_id_to_def_id.insert(ast::CRATE_NODE_ID, root);
+        self.set_invocation_parent(ExpnId::root(), root);
 
-        root_index
+        root
     }
 
     /// Adds a definition with a parent definition.
     pub fn create_def_with_parent(
         &mut self,
-        parent: DefIndex,
+        parent: LocalDefId,
         node_id: ast::NodeId,
         data: DefPathData,
         expn_id: ExpnId,
         span: Span,
-    ) -> DefIndex {
+    ) -> LocalDefId {
         debug!(
             "create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
             parent, node_id, data
         );
 
         assert!(
-            !self.node_to_def_index.contains_key(&node_id),
+            !self.node_id_to_def_id.contains_key(&node_id),
             "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
             node_id,
             data,
-            self.table.def_key(self.node_to_def_index[&node_id])
+            self.table.def_key(self.node_id_to_def_id[&node_id].local_def_index),
         );
 
         // The root node must be created with `create_root_def()`.
@@ -439,59 +439,55 @@ impl Definitions {
         };
 
         let key = DefKey {
-            parent: Some(parent),
+            parent: Some(parent.local_def_index),
             disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
         };
 
-        let parent_hash = self.table.def_path_hash(parent);
+        let parent_hash = self.table.def_path_hash(parent.local_def_index);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
         debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
 
         // Create the definition.
-        let index = self.table.allocate(key, def_path_hash);
-        assert_eq!(index.index(), self.def_index_to_node.len());
-        self.def_index_to_node.push(node_id);
+        let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
 
-        // Some things for which we allocate `DefIndex`es don't correspond to
+        assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
+        assert_eq!(self.def_id_to_span.push(span), def_id);
+
+        // Some things for which we allocate `LocalDefId`s don't correspond to
         // anything in the AST, so they don't have a `NodeId`. For these cases
-        // we don't need a mapping from `NodeId` to `DefIndex`.
+        // we don't need a mapping from `NodeId` to `LocalDefId`.
         if node_id != ast::DUMMY_NODE_ID {
-            debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id);
-            self.node_to_def_index.insert(node_id, index);
+            debug!("create_def_with_parent: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+            self.node_id_to_def_id.insert(node_id, def_id);
         }
 
         if expn_id != ExpnId::root() {
-            self.expansions_that_defined.insert(index, expn_id);
-        }
-
-        // The span is added if it isn't dummy.
-        if !span.is_dummy() {
-            self.def_index_to_span.insert(index, span);
+            self.expansions_that_defined.insert(def_id, expn_id);
         }
 
-        index
+        def_id
     }
 
     /// Initializes the `ast::NodeId` to `HirId` mapping once it has been generated during
     /// AST to HIR lowering.
     pub fn init_node_id_to_hir_id_mapping(&mut self, mapping: IndexVec<ast::NodeId, hir::HirId>) {
         assert!(
-            self.node_to_hir_id.is_empty(),
+            self.node_id_to_hir_id.is_empty(),
             "trying to initialize `NodeId` -> `HirId` mapping twice"
         );
-        self.node_to_hir_id = mapping;
+        self.node_id_to_hir_id = mapping;
 
-        // Build the reverse mapping of `node_to_hir_id`.
-        self.hir_to_node_id = self
-            .node_to_hir_id
+        // Build the reverse mapping of `node_id_to_hir_id`.
+        self.hir_id_to_node_id = self
+            .node_id_to_hir_id
             .iter_enumerated()
             .map(|(node_id, &hir_id)| (hir_id, node_id))
             .collect();
     }
 
-    pub fn expansion_that_defined(&self, index: DefIndex) -> ExpnId {
-        self.expansions_that_defined.get(&index).copied().unwrap_or(ExpnId::root())
+    pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
+        self.expansions_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
     }
 
     pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
@@ -502,13 +498,13 @@ impl Definitions {
         self.parent_modules_of_macro_defs.insert(expn_id, module);
     }
 
-    pub fn invocation_parent(&self, invoc_id: ExpnId) -> DefIndex {
+    pub fn invocation_parent(&self, invoc_id: ExpnId) -> LocalDefId {
         self.invocation_parents[&invoc_id]
     }
 
-    pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: DefIndex) {
+    pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: LocalDefId) {
         let old_parent = self.invocation_parents.insert(invoc_id, parent);
-        assert!(old_parent.is_none(), "parent `DefIndex` is reset for an invocation");
+        assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
     }
 
     pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize {
diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs
index 796f489547269..e3386a2a910ed 100644
--- a/src/librustc/hir/map/hir_id_validator.rs
+++ b/src/librustc/hir/map/hir_id_validator.rs
@@ -3,7 +3,7 @@ use crate::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
@@ -32,7 +32,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 
 struct HirIdValidator<'a, 'hir> {
     hir_map: Map<'hir>,
-    owner_def_index: Option<DefIndex>,
+    owner: Option<LocalDefId>,
     hir_ids_seen: FxHashSet<ItemLocalId>,
     errors: &'a Lock<Vec<String>>,
 }
@@ -46,7 +46,7 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> {
     fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
         HirIdValidator {
             hir_map,
-            owner_def_index: None,
+            owner: None,
             hir_ids_seen: Default::default(),
             errors: self.errors,
         }
@@ -78,12 +78,12 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
     }
 
     fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) {
-        assert!(self.owner_def_index.is_none());
-        let owner_def_index = self.hir_map.local_def_id(hir_id).index;
-        self.owner_def_index = Some(owner_def_index);
+        assert!(self.owner.is_none());
+        let owner = self.hir_map.local_def_id(hir_id).expect_local();
+        self.owner = Some(owner);
         walk(self);
 
-        if owner_def_index == CRATE_DEF_INDEX {
+        if owner.local_def_index == CRATE_DEF_INDEX {
             return;
         }
 
@@ -105,27 +105,26 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
             let mut missing_items = Vec::with_capacity(missing.len());
 
             for local_id in missing {
-                let hir_id =
-                    HirId { owner: owner_def_index, local_id: ItemLocalId::from_u32(local_id) };
+                let hir_id = HirId { owner, local_id: ItemLocalId::from_u32(local_id) };
 
                 trace!("missing hir id {:#?}", hir_id);
 
                 missing_items.push(format!(
                     "[local_id: {}, owner: {}]",
                     local_id,
-                    self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate()
+                    self.hir_map.def_path(owner).to_string_no_crate()
                 ));
             }
             self.error(|| {
                 format!(
                     "ItemLocalIds not assigned densely in {}. \
                 Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
-                    self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
+                    self.hir_map.def_path(owner).to_string_no_crate(),
                     max,
                     missing_items,
                     self.hir_ids_seen
                         .iter()
-                        .map(|&local_id| HirId { owner: owner_def_index, local_id })
+                        .map(|&local_id| HirId { owner, local_id })
                         .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h)))
                         .collect::<Vec<_>>()
                 )
@@ -142,7 +141,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
     }
 
     fn visit_id(&mut self, hir_id: HirId) {
-        let owner = self.owner_def_index.expect("no owner_def_index");
+        let owner = self.owner.expect("no owner");
 
         if hir_id == hir::DUMMY_HIR_ID {
             self.error(|| {
@@ -159,8 +158,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
                 format!(
                     "HirIdValidator: The recorded owner of {} is {} instead of {}",
                     self.hir_map.node_to_string(hir_id),
-                    self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(),
-                    self.hir_map.def_path(DefId::local(owner)).to_string_no_crate()
+                    self.hir_map.def_path(hir_id.owner).to_string_no_crate(),
+                    self.hir_map.def_path(owner).to_string_no_crate()
                 )
             });
         }
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index ba1665fb53083..36cb19c6c37c7 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -9,7 +9,7 @@ use crate::ty::TyCtxt;
 use rustc_ast::ast::{self, Name, NodeId};
 use rustc_data_structures::svh::Svh;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::print::Nested;
@@ -138,7 +138,7 @@ pub struct IndexedHir<'hir> {
     /// The SVH of the local crate.
     pub crate_hash: Svh,
 
-    pub(super) map: IndexVec<DefIndex, HirOwnerData<'hir>>,
+    pub(super) map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
 }
 
 #[derive(Copy, Clone)]
@@ -188,20 +188,19 @@ impl<'hir> Map<'hir> {
         &self.tcx.definitions
     }
 
-    pub fn def_key(&self, def_id: DefId) -> DefKey {
-        assert!(def_id.is_local());
-        self.tcx.definitions.def_key(def_id.index)
+    pub fn def_key(&self, def_id: LocalDefId) -> DefKey {
+        self.tcx.definitions.def_key(def_id)
     }
 
     pub fn def_path_from_hir_id(&self, id: HirId) -> Option<DefPath> {
-        self.opt_local_def_id(id).map(|def_id| self.def_path(def_id))
+        self.opt_local_def_id(id).map(|def_id| self.def_path(def_id.expect_local()))
     }
 
-    pub fn def_path(&self, def_id: DefId) -> DefPath {
-        assert!(def_id.is_local());
-        self.tcx.definitions.def_path(def_id.index)
+    pub fn def_path(&self, def_id: LocalDefId) -> DefPath {
+        self.tcx.definitions.def_path(def_id)
     }
 
+    // FIXME(eddyb) this function can and should return `LocalDefId`.
     #[inline]
     pub fn local_def_id_from_node_id(&self, node: NodeId) -> DefId {
         self.opt_local_def_id_from_node_id(node).unwrap_or_else(|| {
@@ -214,6 +213,7 @@ impl<'hir> Map<'hir> {
         })
     }
 
+    // FIXME(eddyb) this function can and should return `LocalDefId`.
     #[inline]
     pub fn local_def_id(&self, hir_id: HirId) -> DefId {
         self.opt_local_def_id(hir_id).unwrap_or_else(|| {
@@ -228,12 +228,12 @@ impl<'hir> Map<'hir> {
     #[inline]
     pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<DefId> {
         let node_id = self.hir_to_node_id(hir_id);
-        self.tcx.definitions.opt_local_def_id(node_id)
+        self.opt_local_def_id_from_node_id(node_id)
     }
 
     #[inline]
     pub fn opt_local_def_id_from_node_id(&self, node: NodeId) -> Option<DefId> {
-        self.tcx.definitions.opt_local_def_id(node)
+        Some(self.tcx.definitions.opt_local_def_id(node)?.to_def_id())
     }
 
     #[inline]
@@ -256,14 +256,9 @@ impl<'hir> Map<'hir> {
         self.tcx.definitions.node_to_hir_id(node_id)
     }
 
-    #[inline]
-    pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> HirId {
-        self.tcx.definitions.def_index_to_hir_id(def_index)
-    }
-
     #[inline]
     pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId {
-        self.tcx.definitions.def_index_to_hir_id(def_id.to_def_id().index)
+        self.tcx.definitions.local_def_id_to_hir_id(def_id)
     }
 
     pub fn def_kind(&self, hir_id: HirId) -> Option<DefKind> {
@@ -347,10 +342,10 @@ impl<'hir> Map<'hir> {
 
     fn get_entry(&self, id: HirId) -> Entry<'hir> {
         if id.local_id == ItemLocalId::from_u32(0) {
-            let owner = self.tcx.hir_owner(id.owner_def_id());
+            let owner = self.tcx.hir_owner(id.owner);
             Entry { parent: owner.parent, node: owner.node }
         } else {
-            let owner = self.tcx.hir_owner_items(id.owner_def_id());
+            let owner = self.tcx.hir_owner_items(id.owner);
             let item = owner.items[id.local_id].as_ref().unwrap();
             Entry { parent: HirId { owner: id.owner, local_id: item.parent }, node: item.node }
         }
@@ -378,11 +373,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        self.tcx
-            .hir_owner_items(DefId::local(id.hir_id.owner))
-            .bodies
-            .get(&id.hir_id.local_id)
-            .unwrap()
+        self.tcx.hir_owner_items(id.hir_id.owner).bodies.get(&id.hir_id.local_id).unwrap()
     }
 
     pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
@@ -410,6 +401,7 @@ impl<'hir> Map<'hir> {
         parent
     }
 
+    // FIXME(eddyb) this function can and should return `LocalDefId`.
     pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
         self.local_def_id(self.body_owner(id))
     }
@@ -496,7 +488,7 @@ impl<'hir> Map<'hir> {
     where
         V: ItemLikeVisitor<'hir>,
     {
-        let module = self.tcx.hir_module_items(module);
+        let module = self.tcx.hir_module_items(module.expect_local());
 
         for id in &module.items {
             visitor.visit_item(self.expect_item(*id));
@@ -782,6 +774,7 @@ impl<'hir> Map<'hir> {
         scope
     }
 
+    // FIXME(eddyb) this function can and should return `LocalDefId`.
     pub fn get_parent_did(&self, id: HirId) -> DefId {
         self.local_def_id(self.get_parent_item(id))
     }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 3b69fc8d8f2ac..0042b6a3bd42f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -11,7 +11,7 @@ use crate::ty::TyCtxt;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_hir::Body;
 use rustc_hir::HirId;
 use rustc_hir::ItemLocalId;
@@ -60,27 +60,27 @@ impl<'tcx> TyCtxt<'tcx> {
         map::Map { tcx: self }
     }
 
-    pub fn parent_module(self, id: HirId) -> DefId {
-        self.parent_module_from_def_id(DefId::local(id.owner))
+    pub fn parent_module(self, id: HirId) -> LocalDefId {
+        self.parent_module_from_def_id(id.owner)
     }
 }
 
 pub fn provide(providers: &mut Providers<'_>) {
     providers.parent_module_from_def_id = |tcx, id| {
         let hir = tcx.hir();
-        hir.local_def_id(hir.get_module_parent_node(hir.as_local_hir_id(id).unwrap()))
+        hir.local_def_id(hir.get_module_parent_node(hir.as_local_hir_id(id.to_def_id()).unwrap()))
+            .expect_local()
     };
     providers.hir_crate = |tcx, _| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
     providers.hir_module_items = |tcx, id| {
-        assert_eq!(id.krate, LOCAL_CRATE);
         let hir = tcx.hir();
-        let module = hir.as_local_hir_id(id).unwrap();
+        let module = hir.as_local_hir_id(id.to_def_id()).unwrap();
         &tcx.untracked_crate.modules[&module]
     };
-    providers.hir_owner = |tcx, id| tcx.index_hir(id.krate).map[id.index].signature.unwrap();
+    providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature.unwrap();
     providers.hir_owner_items = |tcx, id| {
-        tcx.index_hir(id.krate).map[id.index].with_bodies.as_ref().map(|items| &**items).unwrap()
+        tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|items| &**items).unwrap()
     };
     map::provide(providers);
 }
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 8fd86b3232d00..ba3763f6ee0bd 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIndex};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
@@ -123,16 +123,16 @@ impl<'a> StableHashingContext<'a> {
 
     #[inline]
     pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
-        if def_id.is_local() {
-            self.definitions.def_path_hash(def_id.index)
+        if let Some(def_id) = def_id.as_local() {
+            self.local_def_path_hash(def_id)
         } else {
             self.cstore.def_path_hash(def_id)
         }
     }
 
     #[inline]
-    pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
-        self.definitions.def_path_hash(def_index)
+    pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
+        self.definitions.def_path_hash(def_id)
     }
 
     #[inline]
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 06bfd782b59ce..1722b29266ad2 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -6,7 +6,7 @@ use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext};
 use rustc_attr as attr;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use smallvec::SmallVec;
 use std::mem;
 
@@ -116,8 +116,8 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
     }
 
     #[inline]
-    fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
-        self.local_def_path_hash(def_index)
+    fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
+        self.local_def_path_hash(def_id)
     }
 }
 
@@ -197,21 +197,6 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId {
     }
 }
 
-impl<'a> HashStable<StableHashingContext<'a>> for hir::def_id::DefIndex {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        hcx.local_def_path_hash(*self).hash_stable(hcx, hasher);
-    }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::def_id::DefIndex {
-    type KeyType = DefPathHash;
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
-        hcx.local_def_path_hash(*self)
-    }
-}
-
 impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 758ba4a1ab013..2735c4afca2c8 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -9,7 +9,6 @@
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::{self, DefIdTree, TyCtxt};
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
 
 use rustc_data_structures::fx::FxHashMap;
@@ -594,7 +593,7 @@ impl<'tcx> ScopeTree {
                               region scope tree for {:?} / {:?}",
                             param_owner,
                             self.root_parent.map(|id| tcx.hir().local_def_id(id)),
-                            self.root_body.map(|hir_id| DefId::local(hir_id.owner))
+                            self.root_body.map(|hir_id| hir_id.owner)
                         ),
                     );
                 }
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index ff3a82e53639e..de35c6d87e6f5 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -11,7 +11,7 @@ use crate::ty::query::queries;
 use crate::ty::query::QueryDescription;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 
 use rustc_span::symbol::Symbol;
 use std::borrow::Cow;
@@ -66,24 +66,27 @@ rustc_queries! {
         // The items in a module.
         // This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
         // Avoid calling this query directly.
-        query hir_module_items(key: DefId) -> &'tcx hir::ModuleItems {
+        query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems {
             eval_always
+            desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
         }
 
-        // An HIR item with a `DefId` that can own other HIR items which do not themselves have
-        // a `DefId`.
+        // An HIR item with a `LocalDefId` that can own other HIR items which do
+        // not themselves have a `LocalDefId`.
         // This can be conveniently accessed by methods on `tcx.hir()`.
         // Avoid calling this query directly.
-        query hir_owner(key: DefId) -> &'tcx HirOwner<'tcx> {
+        query hir_owner(key: LocalDefId) -> &'tcx HirOwner<'tcx> {
             eval_always
+            desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
         }
 
-        // The HIR items which do not themselves have a `DefId` and are owned by another HIR item
-        // with a `DefId`.
+        // The HIR items which do not themselves have a `LocalDefId` and are
+        // owned by another HIR item with a `LocalDefId`.
         // This can be conveniently accessed by methods on `tcx.hir()`.
         // Avoid calling this query directly.
-        query hir_owner_items(key: DefId) -> &'tcx HirOwnerItems<'tcx> {
+        query hir_owner_items(key: LocalDefId) -> &'tcx HirOwnerItems<'tcx> {
             eval_always
+            desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
         }
 
         /// Records the type of every item.
@@ -135,8 +138,9 @@ rustc_queries! {
             desc { "computing the lint levels for items in this crate" }
         }
 
-        query parent_module_from_def_id(_: DefId) -> DefId {
+        query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
             eval_always
+            desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
         }
     }
 
@@ -791,7 +795,7 @@ rustc_queries! {
         query specializes(_: (DefId, DefId)) -> bool {
             desc { "computing whether impls specialize one another" }
         }
-        query in_scope_traits_map(_: DefIndex)
+        query in_scope_traits_map(_: LocalDefId)
             -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
             eval_always
             desc { "traits in scope at a block" }
@@ -948,15 +952,15 @@ rustc_queries! {
         query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes {
             desc { "resolving lifetimes" }
         }
-        query named_region_map(_: DefIndex) ->
+        query named_region_map(_: LocalDefId) ->
             Option<&'tcx FxHashMap<ItemLocalId, Region>> {
             desc { "looking up a named region" }
         }
-        query is_late_bound_map(_: DefIndex) ->
+        query is_late_bound_map(_: LocalDefId) ->
             Option<&'tcx FxHashSet<ItemLocalId>> {
             desc { "testing if a region is late bound" }
         }
-        query object_lifetime_defaults_map(_: DefIndex)
+        query object_lifetime_defaults_map(_: LocalDefId)
             -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> {
             desc { "looking up lifetime defaults for a region" }
         }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index d7a259cc87074..742d57fb58a51 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -55,7 +55,7 @@ use rustc_data_structures::stable_hasher::{
 use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::{HirId, Node, TraitCandidate};
 use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet};
 use rustc_index::vec::{Idx, IndexVec};
@@ -205,13 +205,13 @@ fn validate_hir_id_for_typeck_tables(
     mut_access: bool,
 ) {
     if let Some(local_id_root) = local_id_root {
-        if hir_id.owner != local_id_root.index {
+        if hir_id.owner.to_def_id() != local_id_root {
             ty::tls::with(|tcx| {
                 bug!(
                     "node {} with HirId::owner {:?} cannot be placed in \
                      TypeckTables with local_id_root {:?}",
                     tcx.hir().node_to_string(hir_id),
-                    DefId::local(hir_id.owner),
+                    hir_id.owner,
                     local_id_root
                 )
             });
@@ -732,10 +732,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
 
                 let local_id_root = local_id_root.expect("trying to hash invalid TypeckTables");
 
-                let var_owner_def_id =
-                    DefId { krate: local_id_root.krate, index: var_path.hir_id.owner };
+                let var_owner_def_id = DefId {
+                    krate: local_id_root.krate,
+                    index: var_path.hir_id.owner.local_def_index,
+                };
                 let closure_def_id =
-                    DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index };
+                    DefId { krate: local_id_root.krate, index: closure_expr_id.local_def_index };
                 (
                     hcx.def_path_hash(var_owner_def_id),
                     var_path.hir_id.local_id,
@@ -958,7 +960,7 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
-    trait_map: FxHashMap<DefIndex, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
+    trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
 
     /// Export map produced by name resolution.
     export_map: FxHashMap<DefId, Vec<Export<hir::HirId>>>,
@@ -1261,7 +1263,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn def_key(self, id: DefId) -> hir_map::DefKey {
-        if id.is_local() { self.hir().def_key(id) } else { self.cstore.def_key(id) }
+        if let Some(id) = id.as_local() { self.hir().def_key(id) } else { self.cstore.def_key(id) }
     }
 
     /// Converts a `DefId` into its fully expanded `DefPath` (every
@@ -1270,7 +1272,11 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Note that if `id` is not local to this crate, the result will
     ///  be a non-local `DefPath`.
     pub fn def_path(self, id: DefId) -> hir_map::DefPath {
-        if id.is_local() { self.hir().def_path(id) } else { self.cstore.def_path(id) }
+        if let Some(id) = id.as_local() {
+            self.hir().def_path(id)
+        } else {
+            self.cstore.def_path(id)
+        }
     }
 
     /// Returns whether or not the crate with CrateNum 'cnum'
@@ -1281,8 +1287,8 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash {
-        if def_id.is_local() {
-            self.definitions.def_path_hash(def_id.index)
+        if let Some(def_id) = def_id.as_local() {
+            self.definitions.def_path_hash(def_id)
         } else {
             self.cstore.def_path_hash(def_id)
         }
@@ -2747,18 +2753,15 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     };
 
     providers.lookup_stability = |tcx, id| {
-        assert_eq!(id.krate, LOCAL_CRATE);
-        let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
+        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
         tcx.stability().local_stability(id)
     };
     providers.lookup_const_stability = |tcx, id| {
-        assert_eq!(id.krate, LOCAL_CRATE);
-        let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
+        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
         tcx.stability().local_const_stability(id)
     };
     providers.lookup_deprecation_entry = |tcx, id| {
-        assert_eq!(id.krate, LOCAL_CRATE);
-        let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
+        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
         tcx.stability().local_deprecation_entry(id)
     };
     providers.extern_mod_stmt_cnum = |tcx, id| {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 74d677298d3f8..9e3853c51af13 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -384,7 +384,9 @@ impl Visibility {
                 Res::Err => Visibility::Public,
                 def => Visibility::Restricted(def.def_id()),
             },
-            hir::VisibilityKind::Inherited => Visibility::Restricted(tcx.parent_module(id)),
+            hir::VisibilityKind::Inherited => {
+                Visibility::Restricted(tcx.parent_module(id).to_def_id())
+            }
         }
     }
 
@@ -3094,9 +3096,9 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     fn expansion_that_defined(self, scope: DefId) -> ExpnId {
-        match scope.krate {
-            LOCAL_CRATE => self.hir().definitions().expansion_that_defined(scope.index),
-            _ => ExpnId::root(),
+        match scope.as_local() {
+            Some(scope) => self.hir().definitions().expansion_that_defined(scope),
+            None => ExpnId::root(),
         }
     }
 
@@ -3117,7 +3119,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 Some(actual_expansion) => {
                     self.hir().definitions().parent_module_of_macro_def(actual_expansion)
                 }
-                None => self.parent_module(block),
+                None => self.parent_module(block).to_def_id(),
             };
         (ident, scope)
     }
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index 09fb307a1ceb4..6073d3a545f6d 100644
--- a/src/librustc/ty/query/keys.rs
+++ b/src/librustc/ty/query/keys.rs
@@ -7,7 +7,7 @@ use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::query::caches::DefaultCacheSelector;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -84,14 +84,14 @@ impl Key for CrateNum {
     }
 }
 
-impl Key for DefIndex {
+impl Key for LocalDefId {
     type CacheSelector = DefaultCacheSelector;
 
     fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+        self.to_def_id().query_crate()
     }
-    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
-        DUMMY_SP
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.to_def_id().default_span(tcx)
     }
 }
 
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index e3859ed12a2eb..7ac8358c78a61 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -44,7 +44,7 @@ use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
 use rustc_index::vec::IndexVec;
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
@@ -147,7 +147,7 @@ rustc_query_append! { [define_queries!][<'tcx>] }
 ///
 /// When you implement a new query, it will likely have a corresponding new
 /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
-/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter,
+/// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
 /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
 /// add it to the "We don't have enough information to reconstruct..." group in
 /// the match below.
diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs
index 62c2bd801ee33..781abea75d9f7 100644
--- a/src/librustc/ty/query/on_disk_cache.rs
+++ b/src/librustc/ty/query/on_disk_cache.rs
@@ -11,7 +11,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
-use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_serialize::{
@@ -657,26 +656,7 @@ impl<'a, 'tcx> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx> {
     #[inline]
     fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
-        Ok(LocalDefId::from_def_id(DefId::decode(self)?))
-    }
-}
-
-impl<'a, 'tcx> SpecializedDecoder<hir::HirId> for CacheDecoder<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> {
-        // Load the `DefPathHash` which is what we encoded the `DefIndex` as.
-        let def_path_hash = DefPathHash::decode(self)?;
-
-        // Use the `DefPathHash` to map to the current `DefId`.
-        let def_id = self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash];
-
-        debug_assert!(def_id.is_local());
-
-        // The `ItemLocalId` needs no remapping.
-        let local_id = hir::ItemLocalId::decode(self)?;
-
-        // Reconstruct the `HirId` and look up the corresponding `NodeId` in the
-        // context of the current session.
-        Ok(hir::HirId { owner: def_id.index, local_id })
+        Ok(DefId::decode(self)?.expect_local())
     }
 }
 
@@ -873,21 +853,6 @@ where
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<hir::HirId> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + TyEncoder,
-{
-    #[inline]
-    fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> {
-        let hir::HirId { owner, local_id } = *id;
-
-        let def_path_hash = self.tcx.hir().definitions().def_path_hash(owner);
-
-        def_path_hash.encode(self)?;
-        local_id.encode(self)
-    }
-}
-
 impl<'a, 'tcx, E> SpecializedEncoder<DefId> for CacheEncoder<'a, 'tcx, E>
 where
     E: 'a + TyEncoder,
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index aab6aa7c35b0e..94ae2a0973ae9 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -11,7 +11,7 @@ use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
@@ -269,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 hir::ItemKind::Const(ty, body_id)
             }
             ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => {
-                let fn_def_id = self.resolver.definitions().local_def_id(id);
+                let fn_def_id = self.resolver.definitions().local_def_id(id).expect_local();
                 self.with_new_scopes(|this| {
                     this.current_item = Some(ident.span);
 
@@ -287,7 +287,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         AnonymousLifetimeMode::PassThrough,
                         |this, idty| {
                             let ret_id = asyncness.opt_return_id();
-                            this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
+                            this.lower_fn_decl(
+                                &decl,
+                                Some((fn_def_id.to_def_id(), idty)),
+                                true,
+                                ret_id,
+                            )
                         },
                     );
                     let sig = hir::FnSig { decl, header: this.lower_fn_header(header) };
@@ -351,7 +356,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self_ty: ref ty,
                 items: ref impl_items,
             } => {
-                let def_id = self.resolver.definitions().local_def_id(id);
+                let def_id = self.resolver.definitions().local_def_id(id).expect_local();
 
                 // Lower the "impl header" first. This ordering is important
                 // for in-band lifetimes! Consider `'a` here:
@@ -648,7 +653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
-        let def_id = self.resolver.definitions().local_def_id(i.id);
+        let def_id = self.resolver.definitions().local_def_id(i.id).expect_local();
         hir::ForeignItem {
             hir_id: self.lower_node_id(i.id),
             ident: i.ident,
@@ -749,7 +754,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> {
-        let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let trait_item_def_id = self.resolver.definitions().local_def_id(i.id).expect_local();
 
         let (generics, kind) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
@@ -814,7 +819,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> {
-        let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let impl_item_def_id = self.resolver.definitions().local_def_id(i.id).expect_local();
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
@@ -1211,7 +1216,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         generics: &Generics,
         sig: &FnSig,
-        fn_def_id: DefId,
+        fn_def_id: LocalDefId,
         impl_trait_return_allow: bool,
         is_async: Option<NodeId>,
     ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
@@ -1223,7 +1228,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             |this, idty| {
                 this.lower_fn_decl(
                     &sig.decl,
-                    Some((fn_def_id, idty)),
+                    Some((fn_def_id.to_def_id(), idty)),
                     impl_trait_return_allow,
                     is_async,
                 )
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 43a6b7ac04cd9..dcedcd51f5063 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -53,7 +53,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::IndexVec;
@@ -160,7 +160,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 
     type_def_lifetime_params: DefIdMap<usize>,
 
-    current_hir_id_owner: Vec<(DefIndex, u32)>,
+    current_hir_id_owner: Vec<(LocalDefId, u32)>,
     item_local_id_counters: NodeMap<u32>,
     node_id_to_hir_id: IndexVec<NodeId, hir::HirId>,
 
@@ -290,7 +290,7 @@ pub fn lower_crate<'a, 'hir>(
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
         type_def_lifetime_params: Default::default(),
         current_module: hir::CRATE_HIR_ID,
-        current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
+        current_hir_id_owner: vec![(LocalDefId { local_def_index: CRATE_DEF_INDEX }, 0)],
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
         generator_kind: None,
@@ -407,7 +407,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
 
         impl MiscCollector<'_, '_, '_> {
-            fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: DefIndex) {
+            fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefId) {
                 match tree.kind {
                     UseTreeKind::Simple(_, id1, id2) => {
                         for &id in &[id1, id2] {
@@ -463,7 +463,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     | ItemKind::Enum(_, ref generics)
                     | ItemKind::TyAlias(_, ref generics, ..)
                     | ItemKind::Trait(_, _, ref generics, ..) => {
-                        let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
+                        let def_id =
+                            self.lctx.resolver.definitions().local_def_id(item.id).expect_local();
                         let count = generics
                             .params
                             .iter()
@@ -472,7 +473,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 _ => false,
                             })
                             .count();
-                        self.lctx.type_def_lifetime_params.insert(def_id, count);
+                        self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count);
                     }
                     ItemKind::Use(ref use_tree) => {
                         self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner);
@@ -598,12 +599,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             .item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
             .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
-        let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
-        self.current_hir_id_owner.push((def_index, counter));
+        let def_id = self.resolver.definitions().local_def_id(owner).expect_local();
+        self.current_hir_id_owner.push((def_id, counter));
         let ret = f(self);
-        let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
+        let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
 
-        debug_assert!(def_index == new_def_index);
+        debug_assert!(def_id == new_def_id);
         debug_assert!(new_counter >= counter);
 
         let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap();
@@ -619,11 +620,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// properly. Calling the method twice with the same `NodeId` is fine though.
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
         self.lower_node_id_generic(ast_node_id, |this| {
-            let &mut (def_index, ref mut local_id_counter) =
+            let &mut (owner, ref mut local_id_counter) =
                 this.current_hir_id_owner.last_mut().unwrap();
             let local_id = *local_id_counter;
             *local_id_counter += 1;
-            hir::HirId { owner: def_index, local_id: hir::ItemLocalId::from_u32(local_id) }
+            hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
         })
     }
 
@@ -641,12 +642,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
 
             *local_id_counter += 1;
-            let def_index = this.resolver.definitions().opt_def_index(owner).expect(
+            let owner = this.resolver.definitions().opt_local_def_id(owner).expect(
                 "you forgot to call `create_def_with_parent` or are lowering node-IDs \
-                         that do not belong to the current owner",
+                 that do not belong to the current owner",
             );
 
-            hir::HirId { owner: def_index, local_id: hir::ItemLocalId::from_u32(local_id) }
+            hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
         })
     }
 
@@ -724,7 +725,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// parameter while `f` is running (and restored afterwards).
     fn collect_in_band_defs<T>(
         &mut self,
-        parent_id: DefId,
+        parent_def_id: LocalDefId,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
         f: impl FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
     ) -> (Vec<hir::GenericParam<'hir>>, T) {
@@ -744,7 +745,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let params = lifetimes_to_define
             .into_iter()
-            .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_id.index))
+            .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_def_id))
             .chain(in_band_ty_params.into_iter())
             .collect();
 
@@ -756,7 +757,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         span: Span,
         hir_name: ParamName,
-        parent_index: DefIndex,
+        parent_def_id: LocalDefId,
     ) -> hir::GenericParam<'hir> {
         let node_id = self.resolver.next_node_id();
 
@@ -771,7 +772,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // Add a definition for the in-band lifetime def.
         self.resolver.definitions().create_def_with_parent(
-            parent_index,
+            parent_def_id,
             node_id,
             DefPathData::LifetimeNs(str_name),
             ExpnId::root(),
@@ -860,13 +861,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn add_in_band_defs<T>(
         &mut self,
         generics: &Generics,
-        parent_id: DefId,
+        parent_def_id: LocalDefId,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
         f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
     ) -> (hir::Generics<'hir>, T) {
         let (in_band_defs, (mut lowered_generics, res)) =
             self.with_in_scope_lifetime_defs(&generics.params, |this| {
-                this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
+                this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| {
                     let mut params = Vec::new();
                     // Note: it is necessary to lower generics *before* calling `f`.
                     // When lowering `async fn`, there's a final step when lowering
@@ -1048,9 +1049,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // constructing the HIR for `impl bounds...` and then lowering that.
 
                     let impl_trait_node_id = self.resolver.next_node_id();
-                    let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+                    let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
                     self.resolver.definitions().create_def_with_parent(
-                        parent_def_index,
+                        parent_def_id,
                         impl_trait_node_id,
                         DefPathData::ImplTrait,
                         ExpnId::root(),
@@ -1111,12 +1112,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                             // Construct a AnonConst where the expr is the "ty"'s path.
 
-                            let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+                            let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
                             let node_id = self.resolver.next_node_id();
 
                             // Add a definition for the in-band const def.
                             self.resolver.definitions().create_def_with_parent(
-                                parent_def_index,
+                                parent_def_id,
                                 node_id,
                                 DefPathData::AnonConst,
                                 ExpnId::root(),
@@ -1278,8 +1279,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     ImplTraitContext::Universal(in_band_ty_params) => {
                         // Add a definition for the in-band `Param`.
-                        let def_index =
-                            self.resolver.definitions().opt_def_index(def_node_id).unwrap();
+                        let def_id =
+                            self.resolver.definitions().local_def_id(def_node_id).expect_local();
 
                         let hir_bounds = self.lower_param_bounds(
                             bounds,
@@ -1304,7 +1305,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             None,
                             self.arena.alloc(hir::Path {
                                 span,
-                                res: Res::Def(DefKind::TyParam, DefId::local(def_index)),
+                                res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
                                 segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
                             }),
                         ))
@@ -1367,18 +1368,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_index =
-            self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap();
+        let opaque_ty_def_id =
+            self.resolver.definitions().local_def_id(opaque_ty_node_id).expect_local();
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
         let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds);
 
-        let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
-            opaque_ty_node_id,
-            opaque_ty_def_index,
-            &hir_bounds,
-        );
+        let (lifetimes, lifetime_defs) =
+            self.lifetimes_from_impl_trait_bounds(opaque_ty_node_id, opaque_ty_def_id, &hir_bounds);
 
         debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,);
 
@@ -1396,7 +1394,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 origin,
             };
 
-            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
+            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
             let opaque_ty_id =
                 lctx.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span);
 
@@ -1437,14 +1435,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lifetimes_from_impl_trait_bounds(
         &mut self,
         opaque_ty_id: NodeId,
-        parent_index: DefIndex,
+        parent_def_id: LocalDefId,
         bounds: hir::GenericBounds<'hir>,
     ) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) {
         debug!(
             "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
-             parent_index={:?}, \
+             parent_def_id={:?}, \
              bounds={:#?})",
-            opaque_ty_id, parent_index, bounds,
+            opaque_ty_id, parent_def_id, bounds,
         );
 
         // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
@@ -1452,7 +1450,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
         struct ImplTraitLifetimeCollector<'r, 'a, 'hir> {
             context: &'r mut LoweringContext<'a, 'hir>,
-            parent: DefIndex,
+            parent: LocalDefId,
             opaque_ty_id: NodeId,
             collect_elided_lifetimes: bool,
             currently_bound_lifetimes: Vec<hir::LifetimeName>,
@@ -1590,7 +1588,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let mut lifetime_collector = ImplTraitLifetimeCollector {
             context: self,
-            parent: parent_index,
+            parent: parent_def_id,
             opaque_ty_id,
             collect_elided_lifetimes: true,
             currently_bound_lifetimes: Vec::new(),
@@ -1620,12 +1618,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 visitor.visit_ty(ty);
             }
         }
-        let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
+        let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
         let ty = l.ty.as_ref().map(|t| {
             self.lower_ty(
                 t,
                 if self.sess.features_untracked().impl_trait_in_bindings {
-                    ImplTraitContext::OpaqueTy(Some(parent_def_id), hir::OpaqueTyOrigin::Misc)
+                    ImplTraitContext::OpaqueTy(
+                        Some(parent_def_id.to_def_id()),
+                        hir::OpaqueTyOrigin::Misc,
+                    )
                 } else {
                     ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                 },
@@ -1797,8 +1798,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let opaque_ty_def_index =
-            self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap();
+        let opaque_ty_def_id =
+            self.resolver.definitions().local_def_id(opaque_ty_node_id).expect_local();
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
@@ -1886,7 +1887,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
             let generic_params =
                 this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| {
-                    this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_index)
+                    this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id)
                 }));
 
             let opaque_ty_item = hir::OpaqueTy {
@@ -1900,7 +1901,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 origin: hir::OpaqueTyOrigin::AsyncFn,
             };
 
-            trace!("exist ty from async fn def index: {:#?}", opaque_ty_def_index);
+            trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
             let opaque_ty_id =
                 this.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span);
 
diff --git a/src/librustc_hir/hir_id.rs b/src/librustc_hir/hir_id.rs
index a11638a3bb24f..1c7987e965f85 100644
--- a/src/librustc_hir/hir_id.rs
+++ b/src/librustc_hir/hir_id.rs
@@ -1,9 +1,8 @@
-use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
-use rustc_serialize::{self, Decodable, Decoder, Encodable, Encoder};
+use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
 use std::fmt;
 
 /// Uniquely identifies a node in the HIR of the current crate. It is
-/// composed of the `owner`, which is the `DefIndex` of the directly enclosing
+/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
 /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
 /// and the `local_id` which is unique within the given owner.
 ///
@@ -12,41 +11,12 @@ use std::fmt;
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
 pub struct HirId {
-    pub owner: DefIndex,
+    pub owner: LocalDefId,
     pub local_id: ItemLocalId,
 }
 
-impl HirId {
-    pub fn owner_def_id(self) -> DefId {
-        DefId::local(self.owner)
-    }
-
-    pub fn owner_local_def_id(self) -> LocalDefId {
-        LocalDefId::from_def_id(DefId::local(self.owner))
-    }
-}
-
-impl rustc_serialize::UseSpecializedEncodable for HirId {
-    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        let HirId { owner, local_id } = *self;
-
-        owner.encode(s)?;
-        local_id.encode(s)?;
-        Ok(())
-    }
-}
-
-impl rustc_serialize::UseSpecializedDecodable for HirId {
-    fn default_decode<D: Decoder>(d: &mut D) -> Result<HirId, D::Error> {
-        let owner = DefIndex::decode(d)?;
-        let local_id = ItemLocalId::decode(d)?;
-
-        Ok(HirId { owner, local_id })
-    }
-}
-
 impl fmt::Display for HirId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", self)
@@ -70,9 +40,12 @@ rustc_index::newtype_index! {
 rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
-pub const CRATE_HIR_ID: HirId =
-    HirId { owner: CRATE_DEF_INDEX, local_id: ItemLocalId::from_u32(0) };
+pub const CRATE_HIR_ID: HirId = HirId {
+    owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
+    local_id: ItemLocalId::from_u32(0),
+};
 
-pub const DUMMY_HIR_ID: HirId = HirId { owner: CRATE_DEF_INDEX, local_id: DUMMY_ITEM_LOCAL_ID };
+pub const DUMMY_HIR_ID: HirId =
+    HirId { owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, local_id: DUMMY_ITEM_LOCAL_ID };
 
 pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;
diff --git a/src/librustc_hir/stable_hash_impls.rs b/src/librustc_hir/stable_hash_impls.rs
index 7ca2bfded3c2d..996b310896904 100644
--- a/src/librustc_hir/stable_hash_impls.rs
+++ b/src/librustc_hir/stable_hash_impls.rs
@@ -5,7 +5,7 @@ use crate::hir::{
     VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
-use rustc_span::def_id::{DefIndex, DefPathHash};
+use rustc_span::def_id::{DefPathHash, LocalDefId};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
@@ -21,7 +21,7 @@ pub trait HashStableContext:
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
     fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
     fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
-    fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash;
+    fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
diff --git a/src/librustc_lint/internal.rs b/src/librustc_lint/internal.rs
index db109aef6eb8f..d8c685f2b22ff 100644
--- a/src/librustc_lint/internal.rs
+++ b/src/librustc_lint/internal.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
                 }
             }
             TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
-                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) {
+                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
                     if cx.tcx.impl_trait_ref(impl_did).is_some() {
                         return;
                     }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 2ac461a0eb264..229740615f707 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -126,7 +126,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
         ) -> bool {
             if ty.is_unit()
                 || cx.tcx.is_ty_uninhabited_from(
-                    cx.tcx.parent_module(expr.hir_id),
+                    cx.tcx.parent_module(expr.hir_id).to_def_id(),
                     ty,
                     cx.param_env,
                 )
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 9616e1249dc98..f20cdfcba15ca 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -870,11 +870,11 @@ impl<'a> CrateLoader<'a> {
                 let cnum = self.resolve_crate(name, item.span, dep_kind, None);
 
                 let def_id = definitions.opt_local_def_id(item.id).unwrap();
-                let path_len = definitions.def_path(def_id.index).data.len();
+                let path_len = definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
                     cnum,
                     ExternCrate {
-                        src: ExternCrateSource::Extern(def_id),
+                        src: ExternCrateSource::Extern(def_id.to_def_id()),
                         span: item.span,
                         path_len,
                         dependency_of: LOCAL_CRATE,
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 9cad086b4e863..2bf74fe272ec9 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -364,7 +364,7 @@ impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<LocalDefId> for DecodeContext<'a, 'tcx> {
     #[inline]
     fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
-        self.specialized_decode().map(|i| LocalDefId::from_def_id(i))
+        Ok(DefId::decode(self)?.expect_local())
     }
 }
 
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index 98528018d9e80..6280fd62de9a8 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -1350,7 +1350,7 @@ impl EncodeContext<'tcx> {
         let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
         if is_proc_macro {
             let tcx = self.tcx;
-            Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner)))
+            Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)))
         } else {
             None
         }
@@ -1438,8 +1438,8 @@ impl EncodeContext<'tcx> {
             .into_iter()
             .map(|(trait_def_id, mut impls)| {
                 // Bring everything into deterministic order for hashing
-                impls.sort_by_cached_key(|&def_index| {
-                    tcx.hir().definitions().def_path_hash(def_index)
+                impls.sort_by_cached_key(|&index| {
+                    tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index })
                 });
 
                 TraitImpls {
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index ba1b322524e87..077ed49ed2cac 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -272,7 +272,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     // Dump facts if requested.
     let polonius_output = all_facts.and_then(|all_facts| {
         if infcx.tcx.sess.opts.debugging_opts.nll_facts {
-            let def_path = infcx.tcx.hir().def_path(def_id);
+            let def_path = infcx.tcx.def_path(def_id);
             let dir_path =
                 PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
             all_facts.write_to_dir(dir_path, location_table).unwrap();
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index d98abc57bfd49..05d4fc8880e40 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -2008,7 +2008,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 &traits::Obligation::new(
                                     ObligationCause::new(
                                         span,
-                                        self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index),
+                                        self.tcx()
+                                            .hir()
+                                            .local_def_id_to_hir_id(self.mir_def_id.expect_local()),
                                         traits::ObligationCauseCode::RepeatVec(should_suggest),
                                     ),
                                     self.param_env,
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index 67b00e9ffdd5f..c1acd5bd9a691 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -774,9 +774,9 @@ fn for_each_late_bound_region_defined_on<'tcx>(
     fn_def_id: DefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.index) {
+    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
         for late_bound in late_bounds.iter() {
-            let hir_id = HirId { owner: fn_def_id.index, local_id: *late_bound };
+            let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound };
             let name = tcx.hir().name(hir_id);
             let region_def_id = tcx.hir().local_def_id(hir_id);
             let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/src/librustc_mir/const_eval/fn_queries.rs
index 27efcd508414a..470e4e7ed25c1 100644
--- a/src/librustc_mir/const_eval/fn_queries.rs
+++ b/src/librustc_mir/const_eval/fn_queries.rs
@@ -85,7 +85,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
     let parent_id = tcx.hir().get_parent_did(hir_id);
     if !parent_id.is_top_level_module() {
-        is_const_impl_raw(tcx, LocalDefId::from_def_id(parent_id))
+        is_const_impl_raw(tcx, parent_id.expect_local())
     } else {
         false
     }
@@ -171,7 +171,7 @@ fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 pub fn provide(providers: &mut Providers<'_>) {
     *providers = Providers {
         is_const_fn_raw,
-        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, LocalDefId::from_def_id(def_id)),
+        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
         is_promotable_const_fn,
         const_fn_is_allowed_fn_ptr,
         ..*providers
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index 9f04bc1dc7697..02b596863ab40 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -10,7 +10,6 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::ty::{self, AdtKind, Ty};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::Idx;
 use rustc_span::Span;
 
@@ -812,7 +811,7 @@ fn convert_var<'tcx>(
             let closure_def_id = cx.body_owner;
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: LocalDefId::from_def_id(closure_def_id),
+                closure_expr_id: closure_def_id.expect_local(),
             };
             let var_ty = cx.tables().node_type(var_hir_id);
 
@@ -987,7 +986,7 @@ fn capture_upvar<'tcx>(
 ) -> ExprRef<'tcx> {
     let upvar_id = ty::UpvarId {
         var_path: ty::UpvarPath { hir_id: var_hir_id },
-        closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).to_local(),
+        closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).expect_local(),
     };
     let upvar_capture = cx.tables().upvar_capture(upvar_id);
     let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index f71ec5e9ac000..9c86669cf9d92 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -145,7 +145,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
 
     fn check_in_cx(&self, hir_id: HirId, f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>)) {
         let module = self.tcx.parent_module(hir_id);
-        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |cx| f(cx));
+        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module.to_def_id(), |cx| f(cx));
     }
 
     fn check_match(
diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs
index 598d6bb3c4831..7e0d0bfe9aba4 100644
--- a/src/librustc_passes/entry.rs
+++ b/src/librustc_passes/entry.rs
@@ -34,7 +34,7 @@ struct EntryContext<'a, 'tcx> {
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
         let def_id = self.map.local_def_id(item.hir_id);
-        let def_key = self.map.def_key(def_id);
+        let def_key = self.map.def_key(def_id.expect_local());
         let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
         find_item(item, self, at_root);
     }
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index 556d6b40db466..70b106f5d2332 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -1128,7 +1128,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             }
 
             hir::ExprKind::Call(ref f, ref args) => {
-                let m = self.ir.tcx.parent_module(expr.hir_id);
+                let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
                 let succ = if self.ir.tcx.is_ty_uninhabited_from(
                     m,
                     self.tables.expr_ty(expr),
@@ -1143,7 +1143,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             }
 
             hir::ExprKind::MethodCall(.., ref args) => {
-                let m = self.ir.tcx.parent_module(expr.hir_id);
+                let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
                 let succ = if self.ir.tcx.is_ty_uninhabited_from(
                     m,
                     self.tables.expr_ty(expr),
diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs
index 121e03680396c..835e7cfb62816 100644
--- a/src/librustc_passes/reachable.rs
+++ b/src/librustc_passes/reachable.rs
@@ -46,7 +46,7 @@ fn method_might_be_inlined(
     impl_item: &hir::ImplItem<'_>,
     impl_src: DefId,
 ) -> bool {
-    let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner_def_id());
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner.to_def_id());
     let generics = tcx.generics_of(tcx.hir().local_def_id(impl_item.hir_id));
     if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
         return true;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index f5b3de2512527..c8c8c2299305b 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -327,7 +327,7 @@ fn def_id_visibility<'tcx>(
                 }
                 Node::Expr(expr) => {
                     return (
-                        ty::Visibility::Restricted(tcx.parent_module(expr.hir_id)),
+                        ty::Visibility::Restricted(tcx.parent_module(expr.hir_id).to_def_id()),
                         expr.span,
                         "private",
                     );
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index 16359cc743767..505cd331a2509 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::*;
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, FnKind};
 use rustc_expand::expand::AstFragment;
-use rustc_hir::def_id::DefIndex;
+use rustc_hir::def_id::LocalDefId;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
@@ -21,18 +21,18 @@ crate fn collect_definitions(
 /// Creates `DefId`s for nodes in the AST.
 struct DefCollector<'a> {
     definitions: &'a mut Definitions,
-    parent_def: DefIndex,
+    parent_def: LocalDefId,
     expansion: ExpnId,
 }
 
 impl<'a> DefCollector<'a> {
-    fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> DefIndex {
+    fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
         let parent_def = self.parent_def;
         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
         self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
     }
 
-    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
+    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
         let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def);
         f(self);
         self.parent_def = orig_parent_def;
diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs
index 47d04964842e4..51bf1f4843972 100644
--- a/src/librustc_resolve/late/lifetimes.rs
+++ b/src/librustc_resolve/late/lifetimes.rs
@@ -17,7 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
 use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
@@ -280,25 +280,14 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     *providers = ty::query::Providers {
         resolve_lifetimes,
 
-        named_region_map: |tcx, id| {
-            let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
-            tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id)
-        },
-
-        is_late_bound_map: |tcx, id| {
-            let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
-            tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id)
-        },
-
+        named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id),
+        is_late_bound_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id),
         object_lifetime_defaults_map: |tcx, id| {
-            let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
             tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id)
         },
 
         ..*providers
     };
-
-    // (*) FIXME the query should be defined to take a LocalDefId
 }
 
 /// Computes the `ResolveLifetimes` map that contains data for the
@@ -313,15 +302,15 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes
     let mut rl = ResolveLifetimes::default();
 
     for (hir_id, v) in named_region_map.defs {
-        let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default();
+        let map = rl.defs.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
     }
     for hir_id in named_region_map.late_bound {
-        let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default();
+        let map = rl.late_bound.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id);
     }
     for (hir_id, v) in named_region_map.object_lifetime_defaults {
-        let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default();
+        let map = rl.object_lifetime_defaults.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
     }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 8164998d55fd7..4a2a2a296faea 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -37,7 +37,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX};
 use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
 use rustc_hir::{GlobMap, TraitMap};
 use rustc_metadata::creader::{CStore, CrateLoader};
@@ -1015,9 +1015,9 @@ impl<'a> AsMut<Resolver<'a>> for Resolver<'a> {
 
 impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
     fn parent(self, id: DefId) -> Option<DefId> {
-        match id.krate {
-            LOCAL_CRATE => self.definitions.def_key(id.index).parent,
-            _ => self.cstore().def_key(id).parent,
+        match id.as_local() {
+            Some(id) => self.definitions.def_key(id).parent,
+            None => self.cstore().def_key(id).parent,
         }
         .map(|index| DefId { index, ..id })
     }
@@ -1027,7 +1027,11 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
 /// the resolver is no longer needed as all the relevant information is inline.
 impl rustc_ast_lowering::Resolver for Resolver<'_> {
     fn def_key(&mut self, id: DefId) -> DefKey {
-        if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) }
+        if let Some(id) = id.as_local() {
+            self.definitions().def_key(id)
+        } else {
+            self.cstore().def_key(id)
+        }
     }
 
     fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
diff --git a/src/librustc_span/def_id.rs b/src/librustc_span/def_id.rs
index af8d5ce09b52d..29561c91f3318 100644
--- a/src/librustc_span/def_id.rs
+++ b/src/librustc_span/def_id.rs
@@ -164,8 +164,13 @@ impl DefId {
     }
 
     #[inline]
-    pub fn to_local(self) -> LocalDefId {
-        LocalDefId::from_def_id(self)
+    pub fn as_local(self) -> Option<LocalDefId> {
+        if self.is_local() { Some(LocalDefId { local_def_index: self.index }) } else { None }
+    }
+
+    #[inline]
+    pub fn expect_local(self) -> LocalDefId {
+        self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
     }
 
     pub fn is_top_level_module(self) -> bool {
@@ -210,19 +215,26 @@ rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
 /// few cases where we know that only DefIds from the local crate are expected
 /// and a DefId from a different crate would signify a bug somewhere. This
 /// is when LocalDefId comes in handy.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct LocalDefId(DefIndex);
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct LocalDefId {
+    pub local_def_index: DefIndex,
+}
 
-impl LocalDefId {
+impl Idx for LocalDefId {
     #[inline]
-    pub fn from_def_id(def_id: DefId) -> LocalDefId {
-        assert!(def_id.is_local());
-        LocalDefId(def_id.index)
+    fn new(idx: usize) -> Self {
+        LocalDefId { local_def_index: Idx::new(idx) }
     }
+    #[inline]
+    fn index(self) -> usize {
+        self.local_def_index.index()
+    }
+}
 
+impl LocalDefId {
     #[inline]
     pub fn to_def_id(self) -> DefId {
-        DefId { krate: LOCAL_CRATE, index: self.0 }
+        DefId { krate: LOCAL_CRATE, index: self.local_def_index }
     }
 }
 
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index dd03f9358c819..0523a2019861c 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1287,7 +1287,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             let parent = hir.get_parent_node(expr_id);
             if let Some(hir::Node::Expr(e)) = hir.find(parent) {
                 let parent_span = hir.span(parent);
-                let parent_did = parent.owner_def_id();
+                let parent_did = parent.owner.to_def_id();
                 // ```rust
                 // impl T {
                 //     fn foo(&self) -> i32 {}
diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs
index d0d41f3ae32ad..452f965014bff 100644
--- a/src/librustc_trait_selection/traits/object_safety.rs
+++ b/src/librustc_trait_selection/traits/object_safety.rs
@@ -185,7 +185,7 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>
                     .filter_map(|pred| {
                         match pred {
                             hir::WherePredicate::BoundPredicate(pred)
-                                if pred.bounded_ty.hir_id.owner_def_id() == trait_def_id =>
+                                if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
                             {
                                 // Fetch spans for trait bounds that are Sized:
                                 // `trait T where Self: Pred`
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 4531d93c01d27..617c54a738e6e 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1631,7 +1631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) {
-        let generics = self.tcx.generics_of(self.body_id.owner_def_id());
+        let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
         let generic_param = generics.type_param(&param, self.tcx);
         if let ty::GenericParamDefKind::Type { synthetic: Some(..), .. } = generic_param.kind {
             return;
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 94a582dfcfe80..2f0eb5e06709a 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -427,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         });
 
                     if let Some((field, field_ty)) = field_receiver {
-                        let scope = self.tcx.parent_module(self.body_id);
+                        let scope = self.tcx.parent_module(self.body_id).to_def_id();
                         let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
 
                         if is_accessible {
@@ -828,7 +828,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         candidates: Vec<DefId>,
     ) {
         let module_did = self.tcx.parent_module(self.body_id);
-        let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
+        let module_id = self.tcx.hir().as_local_hir_id(module_did.to_def_id()).unwrap();
         let krate = self.tcx.hir().krate();
         let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
         if let Some(span) = span {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index bfb0d25dea208..368f64e4d41aa 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -638,9 +638,8 @@ pub struct InheritedBuilder<'tcx> {
 
 impl Inherited<'_, 'tcx> {
     pub fn build(tcx: TyCtxt<'tcx>, def_id: DefId) -> InheritedBuilder<'tcx> {
-        let hir_id_root = if def_id.is_local() {
-            let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-            DefId::local(hir_id.owner)
+        let hir_id_root = if let Some(def_id) = def_id.as_local() {
+            tcx.hir().local_def_id_to_hir_id(def_id).owner.to_def_id()
         } else {
             def_id
         };
@@ -1128,7 +1127,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
 
     // Consistency check our TypeckTables instance can hold all ItemLocalIds
     // it will need to hold.
-    assert_eq!(tables.local_id_root, Some(DefId::local(id.owner)));
+    assert_eq!(tables.local_id_root, Some(id.owner.to_def_id()));
 
     tables
 }
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 44b960ad22bff..1b5f151870c2f 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for (&var_hir_id, _) in upvars.iter() {
                 let upvar_id = ty::UpvarId {
                     var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: LocalDefId::from_def_id(closure_def_id),
+                    closure_expr_id: closure_def_id.expect_local(),
                 };
                 debug!("seed upvar_id {:?}", upvar_id);
                 // Adding the upvar Id to the list of Upvars, which will be added
@@ -228,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let upvar_ty = self.node_ty(var_hir_id);
                     let upvar_id = ty::UpvarId {
                         var_path: ty::UpvarPath { hir_id: var_hir_id },
-                        closure_expr_id: LocalDefId::from_def_id(closure_def_id),
+                        closure_expr_id: closure_def_id.expect_local(),
                     };
                     let capture = self.tables.borrow().upvar_capture(upvar_id);
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 9d574ee50a4c5..fd92284effb32 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -9,7 +9,7 @@ use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdSet, DefIndex};
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::InferCtxt;
@@ -107,11 +107,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         body: &'tcx hir::Body<'tcx>,
         rustc_dump_user_substs: bool,
     ) -> WritebackCx<'cx, 'tcx> {
-        let owner = body.id().hir_id;
+        let owner = body.id().hir_id.owner;
 
         WritebackCx {
             fcx,
-            tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))),
+            tables: ty::TypeckTables::empty(Some(owner.to_def_id())),
             body,
             rustc_dump_user_substs,
         }
@@ -342,7 +342,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let common_local_id_root = fcx_tables.local_id_root.unwrap();
 
         for (&id, &origin) in fcx_tables.closure_kind_origins().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.index, local_id: id };
+            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id: id };
             self.tables.closure_kind_origins_mut().insert(hir_id, origin);
         }
     }
@@ -364,7 +364,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
         let mut errors_buffer = Vec::new();
         for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.index, local_id };
+            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
 
             if cfg!(debug_assertions) && c_ty.has_local_value() {
                 span_bug!(hir_id.to_span(self.fcx.tcx), "writeback: `{:?}` is a local value", c_ty);
@@ -557,7 +557,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let common_local_id_root = fcx_tables.local_id_root.unwrap();
 
         for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.index, local_id };
+            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
             let fn_sig = self.resolve(fn_sig, &hir_id);
             self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone());
         }
@@ -569,7 +569,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         let common_local_id_root = fcx_tables.local_id_root.unwrap();
 
         for (&local_id, ftys) in fcx_tables.fru_field_types().iter() {
-            let hir_id = hir::HirId { owner: common_local_id_root.index, local_id };
+            let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id };
             let ftys = self.resolve(ftys, &hir_id);
             self.tables.fru_field_types_mut().insert(hir_id, ftys);
         }
@@ -597,13 +597,6 @@ impl Locatable for Span {
     }
 }
 
-impl Locatable for DefIndex {
-    fn to_span(&self, tcx: TyCtxt<'_>) -> Span {
-        let hir_id = tcx.hir().def_index_to_hir_id(*self);
-        tcx.hir().span(hir_id)
-    }
-}
-
 impl Locatable for hir::HirId {
     fn to_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.hir().span(*self)
diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs
index 6666b1699943e..a45d8ce6823a3 100644
--- a/src/librustc_typeck/expr_use_visitor.rs
+++ b/src/librustc_typeck/expr_use_visitor.rs
@@ -519,7 +519,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             for &var_id in upvars.keys() {
                 let upvar_id = ty::UpvarId {
                     var_path: ty::UpvarPath { hir_id: var_id },
-                    closure_expr_id: closure_def_id.to_local(),
+                    closure_expr_id: closure_def_id.expect_local(),
                 };
                 let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
                 let captured_place = return_if_err!(self.cat_captured_var(
diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs
index 4350b3dda97ce..7d8bf71cf97b7 100644
--- a/src/librustc_typeck/mem_categorization.rs
+++ b/src/librustc_typeck/mem_categorization.rs
@@ -470,7 +470,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
         let upvar_id = ty::UpvarId {
             var_path: ty::UpvarPath { hir_id: var_id },
-            closure_expr_id: closure_expr_def_id.to_local(),
+            closure_expr_id: closure_expr_def_id.expect_local(),
         };
         let var_ty = self.node_ty(var_id)?;
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 72106afbe0e75..113c781e33205 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -348,7 +348,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| {
             // FIXME: this fails hard for impls in non-module scope, but is necessary for the
             // current `resolve()` implementation.
-            match self.cx.as_local_hir_id(self.cx.tcx.parent_module(hir_id)).unwrap() {
+            match self.cx.as_local_hir_id(self.cx.tcx.parent_module(hir_id).to_def_id()).unwrap() {
                 id if id != hir_id => Some(id),
                 _ => None,
             }