From 82ded8539e38f6441de852707abbdf872008a340 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 6 Jun 2026 14:23:59 +0200 Subject: [PATCH] Turn `BlockLoc` into a tracked struct, take 3 --- crates/hir-def/src/expr_store/lower.rs | 34 +++--- .../src/expr_store/lower/path/tests.rs | 8 +- .../src/expr_store/tests/body/block.rs | 96 ++++++++++++++++- crates/hir-def/src/find_path.rs | 66 ++++++------ crates/hir-def/src/import_map.rs | 6 +- crates/hir-def/src/item_tree.rs | 8 +- crates/hir-def/src/lib.rs | 100 +++++++++++++----- crates/hir-def/src/nameres.rs | 32 +++--- crates/hir-def/src/resolver.rs | 4 +- crates/hir-def/src/signatures.rs | 9 +- crates/hir-def/src/visibility.rs | 30 +++--- crates/hir-ty/src/lower.rs | 30 +----- crates/hir-ty/src/method_resolution.rs | 47 ++++---- crates/hir/src/lib.rs | 4 +- crates/hir/src/semantics/child_by_source.rs | 2 +- crates/hir/src/source_analyzer.rs | 20 +++- 16 files changed, 325 insertions(+), 171 deletions(-) diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 3094e08a53c3..e6057458bdf0 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -35,8 +35,9 @@ use thin_vec::ThinVec; use tt::TextRange; use crate::{ - AdtId, BlockId, BlockLoc, ConstId, DefWithBodyId, FunctionId, GenericDefId, ImplId, - ItemContainerId, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, + AdtId, BlockId, BlockIdLt, ConstId, DefWithBodyId, FunctionId, GenericDefId, ImplId, + ItemContainerId, LoweringMode, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, + UnresolvedMacro, attrs::AttrFlags, db::DefDatabase, expr_store::{ @@ -85,7 +86,7 @@ pub(super) fn lower_body( let mut self_params = ArrayVec::new(); let mut source_map_self_param = None; let mut params = vec![]; - let mut collector = ExprCollector::new(db, module, current_file_id); + let mut collector = ExprCollector::new(db, module, current_file_id, LoweringMode::Analysis); let skip_body = AttrFlags::query( db, @@ -197,7 +198,8 @@ pub(crate) fn lower_type_ref( module: ModuleId, type_ref: InFile>, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) { - let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id); + let mut expr_collector = + ExprCollector::new(db, module, type_ref.file_id, LoweringMode::Analysis); let type_ref = expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator); let (store, source_map) = expr_collector.store.finish(); @@ -211,8 +213,9 @@ pub fn lower_generic_params( file_id: HirFileId, param_list: Option, where_clause: Option, + mode: LoweringMode, ) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) { - let mut expr_collector = ExprCollector::new(db, module, file_id); + let mut expr_collector = ExprCollector::new(db, module, file_id, mode); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); let params = collector.finish(); @@ -226,7 +229,8 @@ pub(crate) fn lower_impl( impl_syntax: InFile, impl_id: ImplId, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, GenericParams) { - let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id); + let mut expr_collector = + ExprCollector::new(db, module, impl_syntax.file_id, LoweringMode::Analysis); let self_ty = expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty()); let trait_ = impl_syntax.value.trait_().and_then(|it| match &it { @@ -254,7 +258,8 @@ pub(crate) fn lower_trait( trait_syntax: InFile, trait_id: TraitId, ) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) { - let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id); + let mut expr_collector = + ExprCollector::new(db, module, trait_syntax.file_id, LoweringMode::Analysis); let mut collector = generics::GenericParamsCollector::with_self_param( &mut expr_collector, trait_id.into(), @@ -277,7 +282,7 @@ pub(crate) fn lower_type_alias( type_alias_id: TypeAliasId, ) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option) { - let mut expr_collector = ExprCollector::new(db, module, alias.file_id); + let mut expr_collector = ExprCollector::new(db, module, alias.file_id, LoweringMode::Analysis); let bounds = alias .value .type_bound_list() @@ -319,7 +324,7 @@ pub(crate) fn lower_function( bool, bool, ) { - let mut expr_collector = ExprCollector::new(db, module, fn_.file_id); + let mut expr_collector = ExprCollector::new(db, module, fn_.file_id, LoweringMode::Analysis); let mut collector = generics::GenericParamsCollector::new(function_id.into()); collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause()); let mut params = vec![]; @@ -437,6 +442,7 @@ pub struct ExprCollector<'db> { def_map: &'db DefMap, local_def_map: &'db LocalDefMap, module: ModuleId, + lowering_mode: LoweringMode, lang_items: OnceCell<&'db LangItems>, pub store: ExpressionStoreBuilder, @@ -550,6 +556,7 @@ impl<'db> ExprCollector<'db> { db: &dyn DefDatabase, module: ModuleId, current_file_id: HirFileId, + lowering_mode: LoweringMode, ) -> ExprCollector<'_> { let (def_map, local_def_map) = module.local_def_map(db); let expander = Expander::new(db, current_file_id, def_map); @@ -558,6 +565,7 @@ impl<'db> ExprCollector<'db> { db, cfg_options: krate.cfg_options(db), module, + lowering_mode, def_map, local_def_map, lang_items: OnceCell::new(), @@ -2522,10 +2530,12 @@ impl<'db> ExprCollector<'db> { block: ast::BlockExpr, mk_block: impl FnOnce(&mut Self, Option, Box<[Statement]>, Option) -> Expr, ) -> ExprId { - let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| { + let block_id = (|| { + let token = self.lowering_mode.allow_tracked_structs()?; + let file_local_id = self.expander.ast_id_map().ast_id_for_block(&block)?; let ast_id = self.expander.in_file(file_local_id); - BlockId::new(self.db, BlockLoc { ast_id, module: self.module }) - }); + Some(unsafe { BlockIdLt::new(self.db, ast_id, self.module, token).to_static() }) + })(); let (module, def_map) = match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) { diff --git a/crates/hir-def/src/expr_store/lower/path/tests.rs b/crates/hir-def/src/expr_store/lower/path/tests.rs index f507841a91bf..b1d0ebb97d3a 100644 --- a/crates/hir-def/src/expr_store/lower/path/tests.rs +++ b/crates/hir-def/src/expr_store/lower/path/tests.rs @@ -20,8 +20,12 @@ use crate::{ fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option) { let (db, file_id) = TestDB::with_single_file(""); let krate = db.fetch_test_crate(); - let mut ctx = - ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); + let mut ctx = ExprCollector::new( + &db, + crate_def_map(&db, krate).root_module_id(), + file_id.into(), + crate::LoweringMode::Analysis, + ); let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator); let (store, _) = ctx.store.finish(); (db, store, lowered_path) diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs index 906c4835c795..73cc2a5fb38b 100644 --- a/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/crates/hir-def/src/expr_store/tests/body/block.rs @@ -195,9 +195,99 @@ fn f() { Id(2000), ), block: Some( - BlockId( - 4401, - ), + BlockIdLt { + [salsa id]: Id(4401), + ast_id: InFileWrapper { + file_id: FileId( + EditionedFileId { + field: EditionedFileId( + 0, + Edition2024, + ), + }, + ), + value: FileAstId::(ErasedFileAstId { kind: BlockExpr, index: 0, hash: 9730 }), + }, + module: ModuleIdLt { + [salsa id]: Id(3402), + krate: Crate( + Id(2000), + ), + block: Some( + BlockIdLt { + [salsa id]: Id(4400), + ast_id: InFileWrapper { + file_id: FileId( + EditionedFileId { + field: EditionedFileId( + 0, + Edition2024, + ), + }, + ), + value: FileAstId::(ErasedFileAstId { kind: BlockExpr, index: 0, hash: 5EF2 }), + }, + module: ModuleIdLt { + [salsa id]: Id(3400), + krate: Crate( + Id(2000), + ), + block: None, + containing_module_inside_def_map: None, + name_or_empty: Name { + symbol: "", + ctx: (), + }, + }, + }, + ), + containing_module_inside_def_map: Some( + ModuleIdLt { + [salsa id]: Id(3401), + krate: Crate( + Id(2000), + ), + block: Some( + BlockIdLt { + [salsa id]: Id(4400), + ast_id: InFileWrapper { + file_id: FileId( + EditionedFileId { + field: EditionedFileId( + 0, + Edition2024, + ), + }, + ), + value: FileAstId::(ErasedFileAstId { kind: BlockExpr, index: 0, hash: 5EF2 }), + }, + module: ModuleIdLt { + [salsa id]: Id(3400), + krate: Crate( + Id(2000), + ), + block: None, + containing_module_inside_def_map: None, + name_or_empty: Name { + symbol: "", + ctx: (), + }, + }, + }, + ), + containing_module_inside_def_map: None, + name_or_empty: Name { + symbol: "", + ctx: (), + }, + }, + ), + name_or_empty: Name { + symbol: "module", + ctx: (), + }, + }, + }, ), containing_module_inside_def_map: None, name_or_empty: Name { diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 6aaf8a674eee..73e6c18302e3 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -12,7 +12,7 @@ use intern::sym; use rustc_hash::FxHashSet; use crate::{ - FindPathConfig, ModuleDefId, ModuleId, + FindPathConfig, ModuleDefId, ModuleIdLt, db::DefDatabase, import_map::ImportMap, item_scope::ItemInNs, @@ -25,7 +25,7 @@ use crate::{ pub fn find_path( db: &dyn DefDatabase, item: ItemInNs, - from: ModuleId, + from: ModuleIdLt<'_>, mut prefix_kind: PrefixKind, ignore_local_imports: bool, mut cfg: FindPathConfig, @@ -103,14 +103,14 @@ struct FindPathCtx<'db> { cfg: FindPathConfig, ignore_local_imports: bool, is_std_item: bool, - from: ModuleId, + from: ModuleIdLt<'db>, from_crate: Crate, - crate_root: ModuleId, + crate_root: ModuleIdLt<'db>, from_def_map: &'db DefMap, fuel: Cell, } -/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId +/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleIdLt<'_> fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option { // - if the item is a module, jump straight to module search if !ctx.is_std_item @@ -156,10 +156,10 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt } #[tracing::instrument(skip_all)] -fn find_path_for_module( - ctx: &FindPathCtx<'_>, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, - module_id: ModuleId, +fn find_path_for_module<'db>( + ctx: &'db FindPathCtx<'db>, + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, + module_id: ModuleIdLt<'db>, maybe_extern: bool, max_len: usize, ) -> Option { @@ -216,7 +216,7 @@ fn find_path_for_module( ctx.db, ctx.from_def_map, ctx.from, - ItemInNs::Types(module_id.into()), + ItemInNs::Types(unsafe { module_id.to_static() }.into()), ctx.ignore_local_imports, ); if let Some(scope_name) = scope_name { @@ -238,7 +238,7 @@ fn find_path_for_module( } // - if the module is in the prelude, return it by that path - let item = ItemInNs::Types(module_id.into()); + let item = ItemInNs::Types(unsafe { module_id.to_static() }.into()); if let Some(choice) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) { return Some(choice); } @@ -251,10 +251,10 @@ fn find_path_for_module( best_choice } -fn find_in_scope( - db: &dyn DefDatabase, +fn find_in_scope<'db>( + db: &'db dyn DefDatabase, def_map: &DefMap, - from: ModuleId, + from: ModuleIdLt<'db>, item: ItemInNs, ignore_local_imports: bool, ) -> Option { @@ -272,7 +272,7 @@ fn find_in_prelude( db: &dyn DefDatabase, local_def_map: &DefMap, item: ItemInNs, - from: ModuleId, + from: ModuleIdLt<'_>, ) -> Option { let (prelude_module, _) = local_def_map.prelude()?; let prelude_def_map = prelude_module.def_map(db); @@ -304,8 +304,8 @@ fn find_in_prelude( fn is_kw_kind_relative_to_from( db: &dyn DefDatabase, def_map: &DefMap, - item: ModuleId, - from: ModuleId, + item: ModuleIdLt<'_>, + from: ModuleIdLt<'_>, ) -> Option { if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() { return None; @@ -326,9 +326,9 @@ fn is_kw_kind_relative_to_from( } #[tracing::instrument(skip_all)] -fn calculate_best_path( - ctx: &FindPathCtx<'_>, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, +fn calculate_best_path<'db>( + ctx: &'db FindPathCtx<'db>, + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, item: ItemInNs, max_len: usize, best_choice: &mut Option, @@ -366,9 +366,9 @@ fn calculate_best_path( } } -fn find_in_sysroot( - ctx: &FindPathCtx<'_>, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, +fn find_in_sysroot<'db>( + ctx: &'db FindPathCtx<'db>, + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, item: ItemInNs, max_len: usize, best_choice: &mut Option, @@ -412,9 +412,9 @@ fn find_in_sysroot( }); } -fn find_in_dep( - ctx: &FindPathCtx<'_>, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, +fn find_in_dep<'db>( + ctx: &'db FindPathCtx<'db>, + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, item: ItemInNs, max_len: usize, best_choice: &mut Option, @@ -449,9 +449,9 @@ fn find_in_dep( } } -fn calculate_best_path_local( - ctx: &FindPathCtx<'_>, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, +fn calculate_best_path_local<'db>( + ctx: &'db FindPathCtx<'db>, + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, item: ItemInNs, max_len: usize, best_choice: &mut Option, @@ -548,11 +548,11 @@ fn path_kind_len(kind: PathKind) -> usize { } /// Finds locations in `from.krate` from which `item` can be imported by `from`. -fn find_local_import_locations( - ctx: &FindPathCtx<'_>, +fn find_local_import_locations<'db>( + ctx: &'db FindPathCtx<'db>, item: ItemInNs, - visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, - mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId), + visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, + mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, &Name, ModuleIdLt<'db>), ) { let _p = tracing::info_span!("find_local_import_locations").entered(); let db = ctx.db; diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index f8be211bf92a..f57758eb623b 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -533,7 +533,7 @@ mod tests { use expect_test::{Expect, expect}; use test_fixture::WithFixture; - use crate::{ItemContainerId, Lookup, nameres::assoc::TraitItems, test_db::TestDB}; + use crate::{ItemContainerId, Lookup, ModuleIdLt, nameres::assoc::TraitItems, test_db::TestDB}; use super::*; @@ -665,8 +665,8 @@ mod tests { expect.assert_eq(&actual) } - fn render_path(db: &dyn DefDatabase, info: &ImportInfo) -> String { - let mut module = info.container; + fn render_path<'db>(db: &'db dyn DefDatabase, info: &ImportInfo) -> String { + let mut module: ModuleIdLt<'db> = info.container; let mut segments = vec![&info.name]; let def_map = module.def_map(db); diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 4b50161c04cd..78a36fd73137 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -63,7 +63,7 @@ use syntax::{SourceFile, SyntaxKind, ast, match_ast}; use thin_vec::ThinVec; use tt::TextRange; -use crate::{BlockId, Lookup, attrs::parse_extra_crate_attrs, db::DefDatabase}; +use crate::{BlockId, attrs::parse_extra_crate_attrs, db::DefDatabase}; pub(crate) use crate::item_tree::{ attrs::*, @@ -203,10 +203,10 @@ pub(crate) fn block_item_tree_query( krate: Crate, ) -> ItemTree { let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - let loc = block.lookup(db); - let block = loc.ast_id.to_node(db); + let ast_id = block.ast_id(db); + let block = ast_id.to_node(db); - let ctx = lower::Ctx::new(db, loc.ast_id.file_id, krate); + let ctx = lower::Ctx::new(db, ast_id.file_id, krate); let mut item_tree = ctx.lower_block(&block); item_tree.shrink_to_fit(); item_tree diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 2172e2412b89..5c6205bc4afa 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -456,13 +456,68 @@ pub struct ProcMacroLoc { impl_intern!(ProcMacroId, ProcMacroLoc); impl_loc!(ProcMacroLoc, id: Fn, container: ModuleId); -#[derive(Debug, Hash, PartialEq, Eq, Clone)] -pub struct BlockLoc { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] +pub enum LoweringMode { + Analysis, + Ide, +} + +pub use self::tracked_struct_token::TrackedStructToken; +mod tracked_struct_token { + use super::LoweringMode; + + /// A token that is required to construct tracked structs. + /// This exists to prevent one from accidentally creating a tracked struct outside of a query which may happen for some codepaths. + pub struct TrackedStructToken { + // #[non_exhaustive] doesn't work for us here, we want it module focused. + _private: (), + } + + impl LoweringMode { + pub fn allow_tracked_structs(self) -> Option { + match self { + LoweringMode::Analysis => Some(TrackedStructToken { _private: () }), + LoweringMode::Ide => None, + } + } + } +} + +#[salsa_macros::tracked(debug, constructor = new_)] +#[derive(PartialOrd, Ord)] +pub struct BlockIdLt<'db> { pub ast_id: AstId, /// The containing module. - pub module: ModuleId, + pub module: ModuleIdLt<'db>, +} +pub type BlockId = BlockIdLt<'static>; + +impl<'db> BlockIdLt<'db> { + pub fn new( + db: &'db dyn DefDatabase, + ast_id: AstId, + module: ModuleIdLt<'db>, + token: TrackedStructToken, + ) -> Self { + _ = token; + BlockIdLt::new_(db, ast_id, module) + } + + /// # Safety + /// + /// The caller must ensure that the `ModuleId` is not leaked outside of query computations. + pub unsafe fn to_static(self) -> BlockId { + unsafe { std::mem::transmute(self) } + } +} +impl BlockId { + /// # Safety + /// + /// The caller must ensure that the `BlockId` comes from the given database. + pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> BlockIdLt<'db> { + unsafe { std::mem::transmute(self) } + } } -impl_intern!(BlockId, BlockLoc); #[salsa_macros::tracked(debug)] #[derive(PartialOrd, Ord)] @@ -472,7 +527,7 @@ pub struct ModuleIdLt<'db> { /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the /// `BlockId` of that block expression. If `None`, this module is part of the crate-level /// `DefMap` of `krate`. - pub block: Option, + pub block: Option>, /// The parent module of this module, or `None` if this is the root module inside the def /// map (including for block def maps). pub containing_module_inside_def_map: Option>, @@ -481,30 +536,22 @@ pub struct ModuleIdLt<'db> { } pub type ModuleId = ModuleIdLt<'static>; -impl ModuleIdLt<'_> { +impl<'db> ModuleIdLt<'db> { /// # Safety /// /// The caller must ensure that the `ModuleId` is not leaked outside of query computations. pub unsafe fn to_static(self) -> ModuleId { unsafe { std::mem::transmute(self) } } -} -impl ModuleId { - /// # Safety - /// - /// The caller must ensure that the `ModuleId` comes from the given database. - pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> { - unsafe { std::mem::transmute(self) } - } - pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap { + pub fn def_map(self, db: &'db dyn DefDatabase) -> &'db DefMap { match self.block(db) { Some(block) => block_def_map(db, block), None => crate_def_map(db, self.krate(db)), } } - pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) { + pub(crate) fn local_def_map(self, db: &'db dyn DefDatabase) -> (&'db DefMap, &'db LocalDefMap) { match self.block(db) { Some(block) => (block_def_map(db, block), self.only_local_def_map(db)), None => { @@ -514,11 +561,11 @@ impl ModuleId { } } - pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap { + pub(crate) fn only_local_def_map(self, db: &'db dyn DefDatabase) -> &'db LocalDefMap { crate_local_def_map(db, self.krate(db)).local(db) } - pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap { + pub fn crate_def_map(self, db: &'db dyn DefDatabase) -> &'db DefMap { crate_def_map(db, self.krate(db)) } @@ -529,13 +576,9 @@ impl ModuleId { /// Returns the module containing `self`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. - pub fn containing_module(self, db: &dyn DefDatabase) -> Option { + pub fn containing_module(self, db: &'db dyn DefDatabase) -> Option> { self.containing_module_inside_def_map(db) - .or_else(|| self.block(db).map(|block| block.loc(db).module)) - .map(|module| { - // SAFETY: Not sure. - unsafe { module.to_static() } - }) + .or_else(|| self.block(db).map(|block| block.module(db))) } pub fn is_block_module(self, db: &dyn DefDatabase) -> bool { @@ -543,6 +586,15 @@ impl ModuleId { } } +impl ModuleId { + /// # Safety + /// + /// The caller must ensure that the `ModuleId` comes from the given database. + pub unsafe fn to_db<'db>(self, _db: &'db dyn DefDatabase) -> ModuleIdLt<'db> { + unsafe { std::mem::transmute(self) } + } +} + impl HasModule for ModuleId { #[inline] fn module(&self, _db: &dyn DefDatabase) -> ModuleId { diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 0c7e7a3ca070..55b2cf4ac3d5 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -76,7 +76,7 @@ use triomphe::Arc; use tt::TextRange; use crate::{ - AstId, BlockId, BlockLoc, BuiltinDeriveImplId, ExternCrateId, FunctionId, FxIndexMap, Lookup, + AstId, BlockId, BlockIdLt, BuiltinDeriveImplId, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles, MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId, db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, @@ -273,12 +273,12 @@ struct BlockInfo { parent: ModuleId, } -impl std::ops::Index for DefMap { +impl std::ops::Index> for DefMap { type Output = ModuleData; - fn index(&self, id: ModuleId) -> &ModuleData { + fn index(&self, id: ModuleIdLt<'_>) -> &ModuleData { self.modules - .get(&id) + .get(&unsafe { id.to_static() }) .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap {:#?}: {id:#?}", self.root)) } } @@ -426,8 +426,10 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM } #[salsa_macros::tracked(returns(ref))] -pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { - let BlockLoc { ast_id, module } = *block_id.lookup(db); +pub fn block_def_map<'db>(db: &'db dyn DefDatabase, block_id: BlockIdLt<'db>) -> DefMap { + let block_id = unsafe { block_id.to_static() }; + let ast_id = block_id.ast_id(db); + let module = unsafe { block_id.module(db).to_static() }; let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit); let module_data = @@ -615,7 +617,7 @@ impl DefMap { /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. - pub fn containing_module(&self, local_mod: ModuleId) -> Option { + pub fn containing_module(&self, local_mod: ModuleIdLt<'_>) -> Option { match self[local_mod].parent { Some(parent) => Some(parent), None => self.block.map(|BlockInfo { parent, .. }| parent), @@ -720,11 +722,11 @@ impl DefMap { /// /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns /// `None`, iteration continues. - pub(crate) fn with_ancestor_maps( + pub(crate) fn with_ancestor_maps<'db, T>( &self, - db: &dyn DefDatabase, - local_mod: ModuleId, - f: &mut dyn FnMut(&DefMap, ModuleId) -> Option, + db: &'db dyn DefDatabase, + local_mod: ModuleIdLt<'db>, + f: &mut dyn FnMut(&DefMap, ModuleIdLt<'db>) -> Option, ) -> Option { if let Some(it) = f(self, local_mod) { return Some(it); @@ -911,11 +913,13 @@ impl DerefMut for ModulesMap { } } -impl Index for ModulesMap { +impl Index> for ModulesMap { type Output = ModuleData; - fn index(&self, id: ModuleId) -> &ModuleData { - self.inner.get(&id).unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}")) + fn index(&self, id: ModuleIdLt<'_>) -> &ModuleData { + self.inner + .get(&unsafe { id.to_static() }) + .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}")) } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index c16ad9b4f286..b0aa73179add 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -886,7 +886,7 @@ impl<'db> Resolver<'db> { resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })); if let Some(block) = expr_scopes.block(scope_id) { let def_map = block_def_map(db, block); - let local_def_map = block.lookup(db).module.only_local_def_map(db); + let local_def_map = block.module(db).only_local_def_map(db); resolver.scopes.push(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, @@ -1092,7 +1092,7 @@ fn resolver_for_scope_<'db>( for scope in scope_chain.into_iter().rev() { if let Some(block) = scopes.block(scope) { let def_map = block_def_map(db, block); - let local_def_map = block.lookup(db).module.only_local_def_map(db); + let local_def_map = block.module(db).only_local_def_map(db); // Using `DefMap::ROOT` is okay here since inside modules other than the root, // there can't directly be expressions. r = r.push_block_scope(def_map, local_def_map, def_map.root); diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index e9307a125502..c61aaeb73c3d 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -20,8 +20,8 @@ use triomphe::Arc; use crate::{ ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, FxIndexMap, - HasModule, ImplId, ItemContainerId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, - UnionId, VariantId, + HasModule, ImplId, ItemContainerId, LoweringMode, ModuleId, StaticId, StructId, TraitId, + TypeAliasId, UnionId, VariantId, attrs::AttrFlags, db::DefDatabase, expr_store::{ @@ -117,6 +117,7 @@ impl StructSignature { file_id, source.generic_param_list(), source.where_clause(), + LoweringMode::Analysis, ); ( Arc::new(StructSignature { @@ -190,6 +191,7 @@ impl UnionSignature { file_id, source.generic_param_list(), source.where_clause(), + LoweringMode::Analysis, ); ( Arc::new(UnionSignature { @@ -265,6 +267,7 @@ impl EnumSignature { file_id, source.generic_param_list(), source.where_clause(), + LoweringMode::Analysis, ); ( @@ -987,7 +990,7 @@ fn lower_fields( override_visibility: Option>, ) -> Option<(Arena, ExpressionStore, ExpressionStoreSourceMap)> { let cfg_options = module.krate(db).cfg_options(db); - let mut col = ExprCollector::new(db, module, fields.file_id); + let mut col = ExprCollector::new(db, module, fields.file_id, crate::LoweringMode::Analysis); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { let span_map = db.span_map(fields.file_id); diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 81a61ec20f17..7cda95709e76 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -8,8 +8,8 @@ use la_arena::ArenaMap; use syntax::ast::{self, HasVisibility}; use crate::{ - AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId, - db::DefDatabase, nameres::DefMap, resolver::HasResolver, signatures::VariantFields, + AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, ModuleIdLt, TraitId, + VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, signatures::VariantFields, src::HasSource, }; @@ -41,9 +41,13 @@ impl Visibility { } #[tracing::instrument(skip_all)] - pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { + pub fn is_visible_from<'db>( + self, + db: &'db dyn DefDatabase, + from_module: ModuleIdLt<'db>, + ) -> bool { let to_module = match self { - Visibility::Module(m, _) => m, + Visibility::Module(m, _) => unsafe { m.to_db(db) }, Visibility::PubCrate(krate) => return from_module.krate(db) == krate, Visibility::Public => return true, }; @@ -59,11 +63,11 @@ impl Visibility { Self::is_visible_from_def_map_(db, def_map, to_module, from_module) } - pub(crate) fn is_visible_from_def_map( + pub(crate) fn is_visible_from_def_map<'db>( self, - db: &dyn DefDatabase, - def_map: &DefMap, - from_module: ModuleId, + db: &'db dyn DefDatabase, + def_map: &'db DefMap, + from_module: ModuleIdLt<'db>, ) -> bool { if cfg!(debug_assertions) { _ = def_map.modules[from_module]; @@ -89,11 +93,11 @@ impl Visibility { Self::is_visible_from_def_map_(db, def_map, to_module, from_module) } - fn is_visible_from_def_map_( - db: &dyn DefDatabase, - def_map: &DefMap, - mut to_module: ModuleId, - mut from_module: ModuleId, + fn is_visible_from_def_map_<'db>( + db: &'db dyn DefDatabase, + def_map: &'db DefMap, + mut to_module: ModuleIdLt<'db>, + mut from_module: ModuleIdLt<'db>, ) -> bool { debug_assert_eq!(to_module.krate(db), def_map.krate()); // `to_module` might be the root module of a block expression. Those have the same diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index fae63ddc2dea..02005dc9c8fc 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -54,6 +54,9 @@ use stdx::{impl_from, never}; use thin_vec::ThinVec; use tracing::debug; +pub use hir_def::LoweringMode; +pub(crate) use hir_def::TrackedStructToken; + use crate::{ ImplTraitId, Span, TyLoweringDiagnostic, consteval::{create_anon_const, path_to_const}, @@ -199,33 +202,6 @@ pub trait TyLoweringInferVarsCtx<'db> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LoweringMode { - Analysis, - Ide, -} - -pub(crate) use self::tracked_struct_token::TrackedStructToken; -mod tracked_struct_token { - use super::LoweringMode; - - /// A token that is required to construct tracked structs. - /// This exists to prevent one from accidentally creating a tracked struct outside of a query which may happen for some codepaths. - pub(crate) struct TrackedStructToken { - // #[non_exhaustive] doesn't work for us here, we want it module focused. - _private: (), - } - - impl LoweringMode { - pub(crate) fn allow_tracked_structs(self) -> Option { - match self { - LoweringMode::Analysis => Some(TrackedStructToken { _private: () }), - LoweringMode::Ide => None, - } - } - } -} - pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, pub(crate) interner: DbInterner<'db>, diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 9e0188fd2604..6da06594d5bd 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -13,7 +13,7 @@ use tracing::{debug, instrument}; use base_db::Crate; use hir_def::{ - AssocItemId, BlockId, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, + AssocItemId, BlockIdLt, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId, ModuleId, TraitId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, @@ -559,9 +559,9 @@ pub struct InherentImpls { } #[salsa::tracked] -impl InherentImpls { +impl<'db> InherentImpls { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Self { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Self { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -570,7 +570,7 @@ impl InherentImpls { } #[salsa::tracked(returns(ref))] - pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option> { + pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -623,13 +623,13 @@ impl InherentImpls { self.map.get(self_ty).map(|it| &**it).unwrap_or_default() } - pub fn for_each_crate_and_block( - db: &dyn HirDatabase, + pub fn for_each_crate_and_block<'db>( + db: &'db dyn HirDatabase, krate: Crate, - block: Option, + block: Option>, for_each: &mut dyn FnMut(&InherentImpls), ) { - let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db)); + let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); for_each(Self::for_crate(db, krate)); } @@ -668,9 +668,9 @@ pub struct TraitImpls { } #[salsa::tracked] -impl TraitImpls { +impl<'db> TraitImpls { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Arc { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -679,7 +679,7 @@ impl TraitImpls { } #[salsa::tracked(returns(ref))] - pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option> { + pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -688,7 +688,7 @@ impl TraitImpls { } #[salsa::tracked(returns(ref))] - pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc]> { + pub fn for_crate_and_deps(db: &'db dyn HirDatabase, krate: Crate) -> Box<[Arc]> { krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect() } } @@ -817,23 +817,23 @@ impl TraitImpls { } } - pub fn for_each_crate_and_block( - db: &dyn HirDatabase, + pub fn for_each_crate_and_block<'db>( + db: &'db dyn HirDatabase, krate: Crate, - block: Option, + block: Option>, for_each: &mut dyn FnMut(&TraitImpls), ) { - let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db)); + let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each); } /// Like [`Self::for_each_crate_and_block()`], but takes in account two blocks, one for a trait and one for a self type. - pub fn for_each_crate_and_block_trait_and_type( - db: &dyn HirDatabase, + pub fn for_each_crate_and_block_trait_and_type<'db>( + db: &'db dyn HirDatabase, krate: Crate, - type_block: Option, - trait_block: Option, + type_block: Option>, + trait_block: Option>, for_each: &mut dyn FnMut(&TraitImpls), ) { let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate); @@ -844,10 +844,11 @@ impl TraitImpls { // that means there can't be duplicate impls; if they meet, we stop the search of the deeper block. // This breaks when they are equal (both will stop immediately), therefore we handle this case // specifically. - let blocks_iter = |block: Option| { - std::iter::successors(block, |block| block.loc(db).module.block(db)) + let blocks_iter = |block: Option>| { + std::iter::successors(block, |block| block.module(db).block(db)) }; - let for_each_block = |current_block: Option, other_block: Option| { + let for_each_block = |current_block: Option>, + other_block: Option>| { blocks_iter(current_block) .take_while(move |&block| { other_block.is_none_or(|other_block| other_block != block) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index f676a700cc4f..498a91b6298a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -668,7 +668,7 @@ impl Module { while id.is_block_module(db) { id = id.containing_module(db).expect("block without parent module"); } - Module { id } + Module { id: unsafe { id.to_static() } } } pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec { @@ -4717,7 +4717,7 @@ impl Impl { module.block(db), &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))), ); - iter::successors(module.block(db), |block| block.loc(db).module.block(db)) + std::iter::successors(module.block(db), |block| block.module(db).block(db)) .filter_map(|block| TraitImpls::for_block(db, block).as_deref()) .for_each(|impls| impls.for_self_ty(&simplified_ty, &mut extend_with_impls)); for &krate in &*all_crates(db) { diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs index 97c5a451ab6b..15fc81f39bc9 100644 --- a/crates/hir/src/semantics/child_by_source.rs +++ b/crates/hir/src/semantics/child_by_source.rs @@ -228,7 +228,7 @@ impl ChildBySource for DefWithBodyId { // 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); - res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db), block); + res[keys::BLOCK].insert(block.ast_id(db).to_ptr(db), block); } } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 687f130af482..4ffad5ebd0eb 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -13,7 +13,8 @@ use std::{ use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, - FunctionId, GenericDefId, HasModule, LocalFieldId, ModuleDefId, StructId, VariantId, + FunctionId, GenericDefId, HasModule, LocalFieldId, LoweringMode, ModuleDefId, StructId, + VariantId, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, lower::{ExprCollector, lower_generic_params}, @@ -378,8 +379,15 @@ impl<'db> SourceAnalyzer<'db> { }; let generic_def = owner.generic_def(db); let module = generic_def.module(db); - let (store, params, _) = - lower_generic_params(db, module, generic_def, self.file_id, None, Some(where_clause)); + let (store, params, _) = lower_generic_params( + db, + module, + generic_def, + self.file_id, + None, + Some(where_clause), + LoweringMode::Ide, + ); let predicates = params.where_predicates(); if predicates.is_empty() { return PredicateEvaluationResult::holds("predicate does not impose any obligations"); @@ -1274,7 +1282,8 @@ impl<'db> SourceAnalyzer<'db> { } // FIXME: collectiong here shouldnt be necessary? - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = + ExprCollector::new(db, self.resolver.module(), self.file_id, LoweringMode::Ide); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let parent_hir_path = path @@ -1480,7 +1489,8 @@ impl<'db> SourceAnalyzer<'db> { db: &dyn HirDatabase, path: &ast::Path, ) -> Option { - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = + ExprCollector::new(db, self.resolver.module(), self.file_id, LoweringMode::Ide); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let (store, _) = collector.store.finish();