about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-def/src/body/lower.rs2
-rw-r--r--crates/hir-def/src/child_by_source.rs3
-rw-r--r--crates/hir-def/src/db.rs11
-rw-r--r--crates/hir-def/src/import_map.rs6
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs4
-rw-r--r--crates/hir-def/src/nameres.rs57
-rw-r--r--crates/hir-def/src/nameres/collector.rs35
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs29
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs10
-rw-r--r--crates/hir-def/src/resolver.rs8
-rw-r--r--crates/hir-def/src/test_db.rs4
-rw-r--r--crates/hir-ty/src/display.rs3
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs11
-rw-r--r--crates/ide-completion/src/completions.rs2
-rw-r--r--crates/ide-db/src/helpers.rs2
-rw-r--r--crates/ide-db/src/rename.rs2
-rw-r--r--crates/ide-db/src/search.rs6
-rw-r--r--crates/ide-diagnostics/src/handlers/unlinked_file.rs4
-rw-r--r--crates/ide/src/status.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs2
-rw-r--r--lib/la-arena/src/lib.rs16
22 files changed, 130 insertions, 92 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index ebe05afca6a..7055e3ca9e2 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -1073,7 +1073,7 @@ impl ExprCollector<'_> {
             match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
                 Some((def_map, block_id)) => {
                     self.body.block_scopes.push(block_id);
-                    (def_map.module_id(def_map.root()), def_map)
+                    (def_map.module_id(DefMap::ROOT), def_map)
                 }
                 None => (self.expander.module, self.def_map.clone()),
             };
diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs
index 21180fcbdae..bb79e28f267 100644
--- a/crates/hir-def/src/child_by_source.rs
+++ b/crates/hir-def/src/child_by_source.rs
@@ -12,6 +12,7 @@ use crate::{
     db::DefDatabase,
     dyn_map::{keys, DynMap},
     item_scope::ItemScope,
+    nameres::DefMap,
     src::{HasChildSource, HasSource},
     AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, MacroId,
     ModuleDefId, ModuleId, TraitId, VariantId,
@@ -205,7 +206,7 @@ impl ChildBySource for DefWithBodyId {
         for (_, def_map) in body.blocks(db) {
             // All block expressions are merged into the same map, because they logically all add
             // inner items to the containing `DefWithBodyId`.
-            def_map[def_map.root()].scope.child_by_source_to(db, res, file_id);
+            def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id);
         }
     }
 }
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index c3721a94f67..6d18e3f56ca 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -198,15 +198,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
 
     // endregion:attrs
 
-    #[salsa::invoke(LangItems::crate_lang_items_query)]
-    fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
-
     #[salsa::invoke(LangItems::lang_item_query)]
     fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option<LangItemTarget>;
 
     #[salsa::invoke(ImportMap::import_map_query)]
     fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
 
+    // region:visibilities
+
     #[salsa::invoke(visibility::field_visibilities_query)]
     fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
 
@@ -217,8 +216,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[salsa::invoke(visibility::const_visibility_query)]
     fn const_visibility(&self, def: ConstId) -> Visibility;
 
+    // endregion:visibilities
+
+    #[salsa::invoke(LangItems::crate_lang_items_query)]
+    fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
+
     #[salsa::transparent]
     fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
+
     #[salsa::transparent]
     fn recursion_limit(&self, crate_id: CrateId) -> u32;
 
diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs
index 6ef2949ef51..ec150dc0689 100644
--- a/crates/hir-def/src/import_map.rs
+++ b/crates/hir-def/src/import_map.rs
@@ -11,8 +11,8 @@ use rustc_hash::{FxHashSet, FxHasher};
 use triomphe::Arc;
 
 use crate::{
-    db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId,
-    ModuleId, TraitId,
+    db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, visibility::Visibility, AssocItemId,
+    ModuleDefId, ModuleId, TraitId,
 };
 
 type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
@@ -183,7 +183,7 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap {
 
     // We look only into modules that are public(ly reexported), starting with the crate root.
     let empty = ImportPath { segments: vec![] };
-    let root = def_map.module_id(def_map.root());
+    let root = def_map.module_id(DefMap::ROOT);
     let mut worklist = vec![(root, empty)];
     while let Some((module, mod_path)) = worklist.pop() {
         let ext_def_map;
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index 40849d4a66d..4a62696df08 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -35,7 +35,7 @@ use tt::token_id::{Subtree, TokenId};
 use crate::{
     db::DefDatabase,
     macro_id_to_def_id,
-    nameres::{MacroSubNs, ModuleSource},
+    nameres::{DefMap, MacroSubNs, ModuleSource},
     resolver::HasResolver,
     src::HasSource,
     test_db::TestDB,
@@ -61,7 +61,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
     let krate = db.crate_graph().iter().next().unwrap();
     let def_map = db.crate_def_map(krate);
-    let local_id = def_map.root();
+    let local_id = DefMap::ROOT;
     let module = def_map.module_id(local_id);
     let resolver = module.resolver(&db);
     let source = def_map[local_id].definition_source(&db);
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index ccb9bed5c50..053ab5890e4 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -94,7 +94,6 @@ use crate::{
 pub struct DefMap {
     _c: Count<Self>,
     block: Option<BlockInfo>,
-    root: LocalModuleId,
     modules: Arena<ModuleData>,
     krate: CrateId,
     /// The prelude module for this crate. This either comes from an import
@@ -141,7 +140,19 @@ struct BlockInfo {
     /// The `BlockId` this `DefMap` was created from.
     block: BlockId,
     /// The containing module.
-    parent: ModuleId,
+    parent: BlockRelativeModuleId,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+struct BlockRelativeModuleId {
+    block: Option<BlockId>,
+    local_id: LocalModuleId,
+}
+
+impl BlockRelativeModuleId {
+    fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
+        ModuleId { krate, block: self.block, local_id: self.local_id }.def_map(db)
+    }
 }
 
 impl std::ops::Index<LocalModuleId> for DefMap {
@@ -231,6 +242,8 @@ pub struct ModuleData {
 }
 
 impl DefMap {
+    pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
+
     pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
         let _p = profile::span("crate_def_map_query").detail(|| {
             db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string()
@@ -266,7 +279,13 @@ impl DefMap {
             ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
 
         let mut def_map = DefMap::empty(krate, parent_map.edition, module_data);
-        def_map.block = Some(BlockInfo { block: block_id, parent: block.module });
+        def_map.block = Some(BlockInfo {
+            block: block_id,
+            parent: BlockRelativeModuleId {
+                block: block.module.block,
+                local_id: block.module.local_id,
+            },
+        });
 
         let def_map = collector::collect_defs(db, def_map, tree_id);
         Arc::new(def_map)
@@ -275,6 +294,7 @@ impl DefMap {
     fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
         let mut modules: Arena<ModuleData> = Arena::default();
         let root = modules.alloc(module_data);
+        assert_eq!(root, Self::ROOT);
 
         DefMap {
             _c: Count::new(),
@@ -289,7 +309,6 @@ impl DefMap {
             proc_macro_loading_error: None,
             derive_helpers_in_scope: FxHashMap::default(),
             prelude: None,
-            root,
             modules,
             registered_attrs: Vec::new(),
             registered_tools: Vec::new(),
@@ -339,10 +358,6 @@ impl DefMap {
         self.no_std || self.no_core
     }
 
-    pub fn root(&self) -> LocalModuleId {
-        self.root
-    }
-
     pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
         self.fn_proc_macro_mapping.get(&id).copied()
     }
@@ -377,9 +392,9 @@ impl DefMap {
     }
 
     pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
-        self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
+        self.with_ancestor_maps(db, Self::ROOT, &mut |def_map, _module| {
             if def_map.block.is_none() {
-                Some(def_map.module_id(def_map.root))
+                Some(def_map.module_id(Self::ROOT))
             } else {
                 None
             }
@@ -439,7 +454,7 @@ impl DefMap {
         }
         let mut block = self.block;
         while let Some(block_info) = block {
-            let parent = block_info.parent.def_map(db);
+            let parent = block_info.parent.def_map(db, self.krate);
             if let Some(it) = f(&parent, block_info.parent.local_id) {
                 return Some(it);
             }
@@ -452,7 +467,8 @@ impl DefMap {
     /// If this `DefMap` is for a block expression, returns the module containing the block (which
     /// might again be a block, or a module inside a block).
     pub fn parent(&self) -> Option<ModuleId> {
-        Some(self.block?.parent)
+        let BlockRelativeModuleId { block, local_id } = self.block?.parent;
+        Some(ModuleId { krate: self.krate, block, local_id })
     }
 
     /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
@@ -460,7 +476,13 @@ impl DefMap {
     pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
         match self[local_mod].parent {
             Some(parent) => Some(self.module_id(parent)),
-            None => self.block.map(|block| block.parent),
+            None => {
+                self.block.map(
+                    |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
+                        ModuleId { krate: self.krate, block, local_id }
+                    },
+                )
+            }
         }
     }
 
@@ -471,12 +493,12 @@ impl DefMap {
         let mut arc;
         let mut current_map = self;
         while let Some(block) = current_map.block {
-            go(&mut buf, db, current_map, "block scope", current_map.root);
+            go(&mut buf, db, current_map, "block scope", Self::ROOT);
             buf.push('\n');
-            arc = block.parent.def_map(db);
+            arc = block.parent.def_map(db, self.krate);
             current_map = &arc;
         }
-        go(&mut buf, db, current_map, "crate", current_map.root);
+        go(&mut buf, db, current_map, "crate", Self::ROOT);
         return buf;
 
         fn go(
@@ -506,7 +528,7 @@ impl DefMap {
         let mut current_map = self;
         while let Some(block) = current_map.block {
             format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
-            arc = block.parent.def_map(db);
+            arc = block.parent.def_map(db, self.krate);
             current_map = &arc;
         }
 
@@ -534,7 +556,6 @@ impl DefMap {
             recursion_limit: _,
             krate: _,
             prelude: _,
-            root: _,
             rustc_coherence_is_core: _,
             no_core: _,
             no_std: _,
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 64caf26299c..b431b6f6473 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -71,7 +71,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
     for dep in &krate.dependencies {
         tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
         let dep_def_map = db.crate_def_map(dep.crate_id);
-        let dep_root = dep_def_map.module_id(dep_def_map.root);
+        let dep_root = dep_def_map.module_id(DefMap::ROOT);
 
         deps.insert(dep.as_name(), dep_root);
 
@@ -287,7 +287,7 @@ impl DefCollector<'_> {
 
         let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
         let item_tree = self.db.file_item_tree(file_id.into());
-        let module_id = self.def_map.root;
+        let module_id = DefMap::ROOT;
 
         let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
 
@@ -382,7 +382,7 @@ impl DefCollector<'_> {
 
     fn seed_with_inner(&mut self, tree_id: TreeId) {
         let item_tree = tree_id.item_tree(self.db);
-        let module_id = self.def_map.root;
+        let module_id = DefMap::ROOT;
 
         let is_cfg_enabled = item_tree
             .top_level_attrs(self.db, self.def_map.krate)
@@ -464,7 +464,7 @@ impl DefCollector<'_> {
             // Additionally, while the proc macro entry points must be `pub`, they are not publicly
             // exported in type/value namespace. This function reduces the visibility of all items
             // in the crate root that aren't proc macros.
-            let root = self.def_map.root;
+            let root = DefMap::ROOT;
             let module_id = self.def_map.module_id(root);
             let root = &mut self.def_map.modules[root];
             root.scope.censor_non_proc_macros(module_id);
@@ -560,13 +560,8 @@ impl DefCollector<'_> {
         };
         let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]);
 
-        let (per_ns, _) = self.def_map.resolve_path(
-            self.db,
-            self.def_map.root,
-            &path,
-            BuiltinShadowMode::Other,
-            None,
-        );
+        let (per_ns, _) =
+            self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
 
         match per_ns.types {
             Some((ModuleDefId::ModuleId(m), _)) => {
@@ -661,7 +656,7 @@ impl DefCollector<'_> {
         // In Rust, `#[macro_export]` macros are unconditionally visible at the
         // crate root, even if the parent modules is **not** visible.
         if export {
-            let module_id = self.def_map.root;
+            let module_id = DefMap::ROOT;
             self.def_map.modules[module_id].scope.declare(macro_.into());
             self.update(
                 module_id,
@@ -712,7 +707,7 @@ impl DefCollector<'_> {
     /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
     /// And unconditionally exported.
     fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
-        let module_id = self.def_map.root;
+        let module_id = DefMap::ROOT;
         self.def_map.modules[module_id].scope.declare(macro_.into());
         self.update(
             module_id,
@@ -732,7 +727,7 @@ impl DefCollector<'_> {
         let def_map = self.db.crate_def_map(krate);
         // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
         // macros.
-        let root_scope = &def_map[def_map.root].scope;
+        let root_scope = &def_map[DefMap::ROOT].scope;
         if let Some(names) = names {
             for name in names {
                 // FIXME: Report diagnostic on 404.
@@ -834,9 +829,9 @@ impl DefCollector<'_> {
             let root = match self.def_map.block {
                 Some(_) => {
                     let def_map = self.def_map.crate_root(self.db).def_map(self.db);
-                    def_map.module_id(def_map.root())
+                    def_map.module_id(DefMap::ROOT)
                 }
-                None => self.def_map.module_id(self.def_map.root()),
+                None => self.def_map.module_id(DefMap::ROOT),
             };
             Some(root)
         } else {
@@ -879,7 +874,7 @@ impl DefCollector<'_> {
                 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
                 if import.is_extern_crate
                     && self.def_map.block.is_none()
-                    && module_id == self.def_map.root
+                    && module_id == DefMap::ROOT
                 {
                     if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
                     {
@@ -1525,7 +1520,7 @@ impl ModCollector<'_, '_> {
 
     fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
         let krate = self.def_collector.def_map.krate;
-        let is_crate_root = self.module_id == self.def_collector.def_map.root;
+        let is_crate_root = self.module_id == DefMap::ROOT;
 
         // Note: don't assert that inserted value is fresh: it's simply not true
         // for macros.
@@ -1641,9 +1636,9 @@ impl ModCollector<'_, '_> {
                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
-                    if self.def_collector.is_proc_macro && self.module_id == def_map.root {
+                    if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT {
                         if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
-                            let crate_root = def_map.module_id(def_map.root);
+                            let crate_root = def_map.module_id(DefMap::ROOT);
                             self.def_collector.export_proc_macro(
                                 proc_macro,
                                 ItemTreeId::new(self.tree_id, id),
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 24dc4e243bf..751536db384 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -121,7 +121,7 @@ impl DefMap {
             // ...unless we're resolving visibility for an associated item in an impl.
             if self.block_id() != m.block && !within_impl {
                 cov_mark::hit!(adjust_vis_in_block_def_map);
-                vis = Visibility::Module(self.module_id(self.root()));
+                vis = Visibility::Module(self.module_id(Self::ROOT));
                 tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
             }
         }
@@ -173,7 +173,7 @@ impl DefMap {
             match &current_map.block {
                 Some(block) => {
                     original_module = block.parent.local_id;
-                    arc = block.parent.def_map(db);
+                    arc = block.parent.def_map(db, current_map.krate);
                     current_map = &*arc;
                 }
                 None => return result,
@@ -207,7 +207,7 @@ impl DefMap {
                     PerNs::types(self.crate_root(db).into(), Visibility::Public)
                 } else {
                     let def_map = db.crate_def_map(krate);
-                    let module = def_map.module_id(def_map.root);
+                    let module = def_map.module_id(Self::ROOT);
                     cov_mark::hit!(macro_dollar_crate_other);
                     PerNs::types(module.into(), Visibility::Public)
                 }
@@ -268,14 +268,17 @@ impl DefMap {
                                     path.display(db.upcast()),
                                     new_path.display(db.upcast())
                                 );
-                                return block.parent.def_map(db).resolve_path_fp_with_macro(
-                                    db,
-                                    mode,
-                                    block.parent.local_id,
-                                    &new_path,
-                                    shadow,
-                                    expected_macro_subns,
-                                );
+                                return block
+                                    .parent
+                                    .def_map(db, self.krate)
+                                    .resolve_path_fp_with_macro(
+                                        db,
+                                        mode,
+                                        block.parent.local_id,
+                                        &new_path,
+                                        shadow,
+                                        expected_macro_subns,
+                                    );
                             }
                             None => {
                                 tracing::debug!("super path in root module");
@@ -476,9 +479,9 @@ impl DefMap {
         let from_crate_root = match self.block {
             Some(_) => {
                 let def_map = self.crate_root(db).def_map(db);
-                def_map[def_map.root].scope.get(name)
+                def_map[Self::ROOT].scope.get(name)
             }
-            None => self[self.root].scope.get(name),
+            None => self[Self::ROOT].scope.get(name),
         };
         let from_extern_prelude = || {
             self.resolve_name_in_extern_prelude(db, name)
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index 57f0233607b..ae509de0563 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -750,7 +750,7 @@ macro_rules! foo {
 pub use core::clone::Clone;
 "#,
     );
-    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
+    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
@@ -772,7 +772,7 @@ pub macro Copy {}
 pub macro Clone {}
 "#,
     );
-    assert_eq!(map.modules[map.root].scope.impls().len(), 2);
+    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2);
 }
 
 #[test]
@@ -815,7 +815,7 @@ pub macro derive($item:item) {}
 pub macro Clone {}
 "#,
     );
-    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
+    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
@@ -1286,7 +1286,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     let krate = db.crate_graph().iter().next().unwrap();
     let def_map = db.crate_def_map(krate);
 
-    let root_module = &def_map[def_map.root()].scope;
+    let root_module = &def_map[DefMap::ROOT].scope;
     assert!(
         root_module.legacy_macros().count() == 0,
         "`#[macro_use]` shouldn't bring macros into textual macro scope",
@@ -1392,7 +1392,7 @@ macro_rules! derive { () => {} }
 struct S;
     "#,
     );
-    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
+    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 3eaff61b154..06f5b2526a4 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -586,8 +586,9 @@ impl Resolver {
             }));
             if let Some(block) = expr_scopes.block(scope_id) {
                 let def_map = db.block_def_map(block);
-                let root = def_map.root();
-                resolver.scopes.push(Scope::BlockScope(ModuleItemMap { def_map, module_id: root }));
+                resolver
+                    .scopes
+                    .push(Scope::BlockScope(ModuleItemMap { def_map, module_id: DefMap::ROOT }));
                 // FIXME: This adds as many module scopes as there are blocks, but resolving in each
                 // already traverses all parents, so this is O(n²). I think we could only store the
                 // innermost module scope instead?
@@ -753,8 +754,7 @@ fn resolver_for_scope_(
     for scope in scope_chain.into_iter().rev() {
         if let Some(block) = scopes.block(scope) {
             let def_map = db.block_def_map(block);
-            let root = def_map.root();
-            r = r.push_block_scope(def_map, root);
+            r = r.push_block_scope(def_map, DefMap::ROOT);
             // FIXME: This adds as many module scopes as there are blocks, but resolving in each
             // already traverses all parents, so this is O(n²). I think we could only store the
             // innermost module scope instead?
diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs
index d4b40313642..a6befc8a81a 100644
--- a/crates/hir-def/src/test_db.rs
+++ b/crates/hir-def/src/test_db.rs
@@ -110,7 +110,7 @@ impl TestDB {
                 }
                 _ => {
                     // FIXME: handle `mod` inside block expression
-                    return def_map.module_id(def_map.root());
+                    return def_map.module_id(DefMap::ROOT);
                 }
             }
         }
@@ -119,7 +119,7 @@ impl TestDB {
     /// Finds the smallest/innermost module in `def_map` containing `position`.
     fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
         let mut size = None;
-        let mut res = def_map.root();
+        let mut res = DefMap::ROOT;
         for (module, data) in def_map.modules() {
             let src = data.definition_source(self);
             if src.file_id != position.file_id.into() {
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 058d5059b16..32f50cb051d 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -13,6 +13,7 @@ use hir_def::{
     generics::{TypeOrConstParamData, TypeParamProvenance},
     item_scope::ItemInNs,
     lang_item::{LangItem, LangItemTarget},
+    nameres::DefMap,
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
@@ -1488,7 +1489,7 @@ pub fn write_visibility(
         Visibility::Public => write!(f, "pub "),
         Visibility::Module(vis_id) => {
             let def_map = module_id.def_map(f.db.upcast());
-            let root_module_id = def_map.module_id(def_map.root());
+            let root_module_id = def_map.module_id(DefMap::ROOT);
             if vis_id == module_id {
                 // pub(self) or omitted
                 Ok(())
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 0c8793c6df0..9a2090ab79a 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -548,7 +548,7 @@ impl HirDisplay for Module {
         // FIXME: Module doesn't have visibility saved in data.
         match self.name(f.db) {
             Some(name) => write!(f, "mod {}", name.display(f.db.upcast())),
-            None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) {
+            None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) {
                 Some(name) => write!(f, "extern crate {name}"),
                 None => f.write_str("extern crate {unknown}"),
             },
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7c432197a60..19709bb44ad 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -118,7 +118,7 @@ pub use {
         find_path::PrefixKind,
         import_map,
         lang_item::LangItem,
-        nameres::ModuleSource,
+        nameres::{DefMap, ModuleSource},
         path::{ModPath, PathKind},
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
@@ -202,7 +202,7 @@ impl Crate {
 
     pub fn root_module(self, db: &dyn HirDatabase) -> Module {
         let def_map = db.crate_def_map(self.id);
-        Module { id: def_map.module_id(def_map.root()) }
+        Module { id: def_map.module_id(DefMap::ROOT) }
     }
 
     pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -475,12 +475,11 @@ impl Module {
     /// in the module tree of any target in `Cargo.toml`.
     pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
         let def_map = db.crate_def_map(self.id.krate());
-        Module { id: def_map.module_id(def_map.root()) }
+        Module { id: def_map.module_id(DefMap::ROOT) }
     }
 
-    pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
-        let def_map = db.crate_def_map(self.id.krate());
-        def_map.root() == self.id.local_id
+    pub fn is_crate_root(self) -> bool {
+        DefMap::ROOT == self.id.local_id
     }
 
     /// Iterates over all child modules.
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index d53e9e2fa90..480cb77b4fd 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -158,7 +158,7 @@ impl Completions {
         path_ctx: &PathCompletionCtx,
     ) {
         ctx.process_all_names(&mut |name, res, doc_aliases| match res {
-            ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
+            ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => {
                 self.add_module(ctx, path_ctx, m, name, doc_aliases);
             }
             _ => (),
diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs
index 8e3b1eef15b..eba9d8afc40 100644
--- a/crates/ide-db/src/helpers.rs
+++ b/crates/ide-db/src/helpers.rs
@@ -77,7 +77,7 @@ pub fn visit_file_defs(
     }
     module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
 
-    let is_root = module.is_crate_root(db);
+    let is_root = module.is_crate_root();
     module
         .legacy_macros(db)
         .into_iter()
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index 5b2558ea8fe..52a23b4b8f3 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -178,7 +178,7 @@ fn rename_mod(
 
     let mut source_change = SourceChange::default();
 
-    if module.is_crate_root(sema.db) {
+    if module.is_crate_root() {
         return Ok(source_change);
     }
 
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index 9d00c717097..73cd5dcaf23 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -225,7 +225,7 @@ impl Definition {
         // def is crate root
         // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
         if let &Definition::Module(module) = self {
-            if module.is_crate_root(db) {
+            if module.is_crate_root() {
                 return SearchScope::reverse_dependencies(db, module.krate());
             }
         }
@@ -392,7 +392,7 @@ impl<'a> FindUsages<'a> {
 
         let name = match self.def {
             // special case crate modules as these do not have a proper name
-            Definition::Module(module) if module.is_crate_root(self.sema.db) => {
+            Definition::Module(module) if module.is_crate_root() => {
                 // FIXME: This assumes the crate name is always equal to its display name when it really isn't
                 module
                     .krate()
@@ -500,7 +500,7 @@ impl<'a> FindUsages<'a> {
             let scope =
                 search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module));
 
-            let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
+            let is_crate_root = module.is_crate_root().then(|| Finder::new("crate"));
             let finder = &Finder::new("super");
 
             for (text, file_id, search_range) in scope_files(sema, &scope) {
diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index b9c5384ea1e..271e7ce73bc 100644
--- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -2,7 +2,7 @@
 
 use std::iter;
 
-use hir::{db::DefDatabase, InFile, ModuleSource};
+use hir::{db::DefDatabase, DefMap, InFile, ModuleSource};
 use ide_db::{
     base_db::{FileId, FileLoader, SourceDatabase, SourceDatabaseExt},
     source_change::SourceChange,
@@ -74,7 +74,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option<Vec<Assist>> {
     'crates: for &krate in &*ctx.sema.db.relevant_crates(file_id) {
         let crate_def_map = ctx.sema.db.crate_def_map(krate);
 
-        let root_module = &crate_def_map[crate_def_map.root()];
+        let root_module = &crate_def_map[DefMap::ROOT];
         let Some(root_file_id) = root_module.origin.file_id() else { continue };
         let Some(crate_root_path) = source_root.path_for_file(&root_file_id) else { continue };
         let Some(rel) = parent.strip_prefix(&crate_root_path.parent()?) else { continue };
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index 70bff41121d..d2c77e2dc79 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -1,7 +1,7 @@
 use std::{fmt, marker::PhantomData};
 
 use hir::{
-    db::{AstIdMapQuery, AttrsQuery, ParseMacroExpansionQuery},
+    db::{AstIdMapQuery, AttrsQuery, BlockDefMapQuery, ParseMacroExpansionQuery},
     Attr, Attrs, ExpandResult, MacroFile, Module,
 };
 use ide_db::{
@@ -51,6 +51,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
     format_to!(buf, "\nDebug info:\n");
     format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db)));
     format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db)));
+    format_to!(buf, "{} block def maps\n", collect_query_count(BlockDefMapQuery.in_db(db)));
 
     if let Some(file_id) = file_id {
         format_to!(buf, "\nFile info:\n");
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 925057ffaa0..3c40246a69d 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -340,7 +340,7 @@ fn highlight_def(
         Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
         Definition::Module(module) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module));
-            if module.is_crate_root(db) {
+            if module.is_crate_root() {
                 h |= HlMod::CrateRoot;
             }
             h
diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs
index 1f8ef01a5bc..5107f294394 100644
--- a/lib/la-arena/src/lib.rs
+++ b/lib/la-arena/src/lib.rs
@@ -18,6 +18,18 @@ pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry};
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct RawIdx(u32);
 
+impl RawIdx {
+    /// Constructs a [`RawIdx`] from a u32.
+    pub const fn from_u32(u32: u32) -> Self {
+        RawIdx(u32)
+    }
+
+    /// Deconstructs a [`RawIdx`] into the underlying u32.
+    pub const fn into_u32(self) -> u32 {
+        self.0
+    }
+}
+
 impl From<RawIdx> for u32 {
     #[inline]
     fn from(raw: RawIdx) -> u32 {
@@ -94,12 +106,12 @@ impl<T> fmt::Debug for Idx<T> {
 
 impl<T> Idx<T> {
     /// Creates a new index from a [`RawIdx`].
-    pub fn from_raw(raw: RawIdx) -> Self {
+    pub const fn from_raw(raw: RawIdx) -> Self {
         Idx { raw, _ty: PhantomData }
     }
 
     /// Converts this index into the underlying [`RawIdx`].
-    pub fn into_raw(self) -> RawIdx {
+    pub const fn into_raw(self) -> RawIdx {
         self.raw
     }
 }