Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/lib.rs')
-rw-r--r--crates/hir-def/src/lib.rs114
1 files changed, 89 insertions, 25 deletions
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index fa7cb525bb..8b93fe5e2f 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -50,7 +50,10 @@ mod macro_expansion_tests;
#[cfg(test)]
mod test_db;
-use std::hash::{Hash, Hasher};
+use std::{
+ fmt,
+ hash::{Hash, Hasher},
+};
use base_db::{Crate, SourceDatabase, impl_intern_key};
use hir_expand::{
@@ -462,13 +465,74 @@ 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<TrackedStructToken> {
+ match self {
+ LoweringMode::Analysis => Some(TrackedStructToken { _private: () }),
+ LoweringMode::Ide => None,
+ }
+ }
+ }
+}
+
+#[salsa_macros::tracked(constructor = new_)]
+#[derive(PartialOrd, Ord)]
+pub struct BlockIdLt<'db> {
pub ast_id: AstId<ast::BlockExpr>,
/// The containing module.
- pub module: ModuleId,
+ pub module: ModuleIdLt<'db>,
+}
+pub type BlockId = BlockIdLt<'static>;
+
+impl<'db> fmt::Debug for BlockIdLt<'db> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("BlockId").field(&self.0).finish()
+ }
+}
+
+impl<'db> BlockIdLt<'db> {
+ pub fn new(
+ db: &'db dyn SourceDatabase,
+ ast_id: AstId<ast::BlockExpr>,
+ 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 SourceDatabase) -> BlockIdLt<'db> {
+ unsafe { std::mem::transmute(self) }
+ }
}
-impl_intern!(BlockId, BlockLoc);
#[salsa_macros::tracked(debug)]
#[derive(PartialOrd, Ord)]
@@ -478,7 +542,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<BlockId>,
+ pub block: Option<BlockIdLt<'db>>,
/// 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<ModuleIdLt<'db>>,
@@ -487,30 +551,25 @@ 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 SourceDatabase) -> ModuleIdLt<'db> {
- unsafe { std::mem::transmute(self) }
- }
- pub fn def_map(self, db: &dyn SourceDatabase) -> &DefMap {
+ pub fn def_map(self, db: &'db dyn SourceDatabase) -> &'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 SourceDatabase) -> (&DefMap, &LocalDefMap) {
+ pub(crate) fn local_def_map(
+ self,
+ db: &'db dyn SourceDatabase,
+ ) -> (&'db DefMap, &'db LocalDefMap) {
match self.block(db) {
Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
None => {
@@ -520,11 +579,11 @@ impl ModuleId {
}
}
- pub(crate) fn only_local_def_map(self, db: &dyn SourceDatabase) -> &LocalDefMap {
+ pub(crate) fn only_local_def_map(self, db: &'db dyn SourceDatabase) -> &'db LocalDefMap {
crate_local_def_map(db, self.krate(db)).local(db)
}
- pub fn crate_def_map(self, db: &dyn SourceDatabase) -> &DefMap {
+ pub fn crate_def_map(self, db: &'db dyn SourceDatabase) -> &'db DefMap {
crate_def_map(db, self.krate(db))
}
@@ -535,13 +594,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 SourceDatabase) -> Option<ModuleId> {
+ pub fn containing_module(self, db: &'db dyn SourceDatabase) -> Option<ModuleIdLt<'db>> {
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 SourceDatabase) -> bool {
@@ -549,6 +604,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 SourceDatabase) -> ModuleIdLt<'db> {
+ unsafe { std::mem::transmute(self) }
+ }
+}
+
impl HasModule for ModuleId {
#[inline]
fn module(&self, _db: &dyn SourceDatabase) -> ModuleId {