internal: Give FileSymbol it's 'db lifetime

This commit is contained in:
Lukas Wirth 2025-12-07 14:50:24 +01:00
parent 30332663cb
commit aecd399ac8
9 changed files with 129 additions and 75 deletions

View file

@ -59,6 +59,28 @@ macro_rules! impl_intern_key {
};
}
/// # SAFETY
///
/// `old_pointer` must be valid for unique writes
pub unsafe fn unsafe_update_eq<T>(old_pointer: *mut T, new_value: T) -> bool
where
T: PartialEq,
{
// SAFETY: Caller obligation
let old_ref: &mut T = unsafe { &mut *old_pointer };
if *old_ref != new_value {
*old_ref = new_value;
true
} else {
// Subtle but important: Eq impls can be buggy or define equality
// in surprising ways. If it says that the value has not changed,
// we do not modify the existing value, and thus do not have to
// update the revision, as downstream code will not see the new value.
false
}
}
pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16;
pub const DEFAULT_PARSE_LRU_CAP: u16 = 128;
pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024;

View file

@ -4,42 +4,5 @@
//!
//! But we need this for at least LRU caching at the query level.
pub use hir_def::db::DefDatabase;
// AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
// BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
// CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
// DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
// ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
// FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
// FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
// GenericParamsWithSourceMapQuery, ImplItemsWithDiagnosticsQuery, ImportMapQuery,
// IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
// InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
// InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
// InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
// InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
// InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
// MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
// StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitItemsWithDiagnosticsQuery,
// TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
// };
pub use hir_expand::db::ExpandDatabase;
// AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
// ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
// ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
// RealSpanMapQuery,
pub use hir_ty::db::HirDatabase;
// AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
// CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
// ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
// FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
// GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
// ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
// InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
// InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
// InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
// MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
// MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
// TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
// TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
// TypeAliasImplTraitsQuery, ValueTyQuery,
// };

View file

@ -1,5 +1,7 @@
//! File symbol extraction.
use std::marker::PhantomData;
use base_db::FxIndexSet;
use either::Either;
use hir_def::{
@ -25,7 +27,7 @@ use crate::{HasCrate, Module, ModuleDef, Semantics};
/// The actual data that is stored in the index. It should be as compact as
/// possible.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FileSymbol {
pub struct FileSymbol<'db> {
pub name: Symbol,
pub def: ModuleDef,
pub loc: DeclarationLocation,
@ -35,6 +37,7 @@ pub struct FileSymbol {
pub is_assoc: bool,
pub is_import: bool,
pub do_not_complete: Complete,
_marker: PhantomData<&'db ()>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -61,9 +64,9 @@ struct SymbolCollectorWork {
parent: Option<Name>,
}
pub struct SymbolCollector<'a> {
db: &'a dyn HirDatabase,
symbols: FxIndexSet<FileSymbol>,
pub struct SymbolCollector<'db> {
db: &'db dyn HirDatabase,
symbols: FxIndexSet<FileSymbol<'db>>,
work: Vec<SymbolCollectorWork>,
current_container_name: Option<Symbol>,
collect_pub_only: bool,
@ -83,10 +86,10 @@ impl<'a> SymbolCollector<'a> {
}
pub fn new_module(
db: &dyn HirDatabase,
db: &'a dyn HirDatabase,
module: Module,
collect_pub_only: bool,
) -> Box<[FileSymbol]> {
) -> Box<[FileSymbol<'a>]> {
let mut symbol_collector = SymbolCollector::new(db, collect_pub_only);
symbol_collector.collect(module);
symbol_collector.finish()
@ -105,7 +108,7 @@ impl<'a> SymbolCollector<'a> {
}
}
pub fn finish(self) -> Box<[FileSymbol]> {
pub fn finish(self) -> Box<[FileSymbol<'a>]> {
self.symbols.into_iter().collect()
}
@ -217,6 +220,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: true,
do_not_complete: Complete::Yes,
_marker: PhantomData,
});
};
@ -251,6 +255,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete: Complete::Yes,
_marker: PhantomData,
});
};
@ -428,6 +433,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc,
is_import: false,
do_not_complete,
_marker: PhantomData,
});
}
}
@ -441,6 +447,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc,
is_import: false,
do_not_complete,
_marker: PhantomData,
});
do_not_complete
@ -474,6 +481,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete,
_marker: PhantomData,
});
}
}
@ -487,6 +495,7 @@ impl<'a> SymbolCollector<'a> {
is_assoc: false,
is_import: false,
do_not_complete,
_marker: PhantomData,
});
}
}

View file

@ -37,6 +37,7 @@ use hir::{
};
use rayon::prelude::*;
use rustc_hash::FxHashSet;
use salsa::Update;
use crate::RootDatabase;
@ -118,7 +119,7 @@ pub struct LocalRoots {
}
/// The symbol indices of modules that make up a given crate.
pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> {
pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_>]> {
let _p = tracing::info_span!("crate_symbols").entered();
krate.modules(db).into_iter().map(|module| SymbolIndex::module_symbols(db, module)).collect()
}
@ -148,7 +149,7 @@ pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]>
// | Editor | Shortcut |
// |---------|-----------|
// | VS Code | <kbd>Ctrl+T</kbd>
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol<'_>> {
let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
let indices: Vec<_> = if query.libs {
@ -170,9 +171,7 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
crates
.par_iter()
.for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into()));
let indices: Vec<_> =
crates.into_iter().map(|krate| crate_symbols(db, krate.into())).collect();
indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
crates.into_iter().flat_map(|krate| Vec::from(crate_symbols(db, krate.into()))).collect()
};
let mut res = vec![];
@ -184,24 +183,27 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
}
#[derive(Default)]
pub struct SymbolIndex {
symbols: Box<[FileSymbol]>,
pub struct SymbolIndex<'db> {
symbols: Box<[FileSymbol<'db>]>,
map: fst::Map<Vec<u8>>,
}
impl SymbolIndex {
impl<'db> SymbolIndex<'db> {
/// The symbol index for a given source root within library_roots.
pub fn library_symbols(db: &dyn HirDatabase, source_root_id: SourceRootId) -> &SymbolIndex {
pub fn library_symbols(
db: &'db dyn HirDatabase,
source_root_id: SourceRootId,
) -> &'db SymbolIndex<'db> {
// FIXME:
#[salsa::interned]
struct InternedSourceRootId {
id: SourceRootId,
}
#[salsa::tracked(returns(ref))]
fn library_symbols(
db: &dyn HirDatabase,
source_root_id: InternedSourceRootId<'_>,
) -> SymbolIndex {
fn library_symbols<'db>(
db: &'db dyn HirDatabase,
source_root_id: InternedSourceRootId<'db>,
) -> SymbolIndex<'db> {
let _p = tracing::info_span!("library_symbols").entered();
// We call this without attaching because this runs in parallel, so we need to attach here.
@ -224,7 +226,7 @@ impl SymbolIndex {
/// The symbol index for a given module. These modules should only be in source roots that
/// are inside local_roots.
pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex {
pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex<'_> {
// FIXME:
#[salsa::interned]
struct InternedModuleId {
@ -232,7 +234,10 @@ impl SymbolIndex {
}
#[salsa::tracked(returns(ref))]
fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolIndex {
fn module_symbols<'db>(
db: &'db dyn HirDatabase,
module: InternedModuleId<'db>,
) -> SymbolIndex<'db> {
let _p = tracing::info_span!("module_symbols").entered();
// We call this without attaching because this runs in parallel, so we need to attach here.
@ -250,29 +255,41 @@ impl SymbolIndex {
}
}
impl fmt::Debug for SymbolIndex {
impl fmt::Debug for SymbolIndex<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
}
}
impl PartialEq for SymbolIndex {
fn eq(&self, other: &SymbolIndex) -> bool {
impl PartialEq for SymbolIndex<'_> {
fn eq(&self, other: &SymbolIndex<'_>) -> bool {
self.symbols == other.symbols
}
}
impl Eq for SymbolIndex {}
impl Eq for SymbolIndex<'_> {}
impl Hash for SymbolIndex {
impl Hash for SymbolIndex<'_> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.symbols.hash(hasher)
}
}
impl SymbolIndex {
fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex {
fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
unsafe impl Update for SymbolIndex<'_> {
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
let this = unsafe { &mut *old_pointer };
if *this == new_value {
false
} else {
*this = new_value;
true
}
}
}
impl<'db> SymbolIndex<'db> {
fn new(mut symbols: Box<[FileSymbol<'db>]>) -> SymbolIndex<'db> {
fn cmp(lhs: &FileSymbol<'_>, rhs: &FileSymbol<'_>) -> Ordering {
let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase());
lhs_chars.cmp(rhs_chars)
@ -318,7 +335,7 @@ impl SymbolIndex {
}
pub fn memory_size(&self) -> usize {
self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol>()
self.map.as_fst().size() + self.symbols.len() * size_of::<FileSymbol<'_>>()
}
fn range_to_map_value(start: usize, end: usize) -> u64 {
@ -336,10 +353,10 @@ impl SymbolIndex {
}
impl Query {
pub(crate) fn search<'sym, T>(
pub(crate) fn search<'db, T>(
self,
indices: &'sym [&SymbolIndex],
cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
indices: &[&'db SymbolIndex<'db>],
cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
) -> Option<T> {
let _p = tracing::info_span!("symbol_index::Query::search").entered();
let mut op = fst::map::OpBuilder::new();
@ -371,11 +388,11 @@ impl Query {
}
}
fn search_maps<'sym, T>(
fn search_maps<'db, T>(
&self,
indices: &'sym [&SymbolIndex],
indices: &[&'db SymbolIndex<'db>],
mut stream: fst::map::Union<'_>,
mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
mut cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow<T>,
) -> Option<T> {
let ignore_underscore_prefixed = !self.query.starts_with("__");
while let Some((_, indexed_values)) = stream.next() {

View file

@ -39,6 +39,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Struct",
@ -73,6 +74,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "mul1",
@ -107,6 +109,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "mul2",
@ -141,6 +144,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "s1",
@ -175,6 +179,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "s1",
@ -209,6 +214,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "s2",
@ -243,6 +249,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
],
),

View file

@ -39,6 +39,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Alias",
@ -71,6 +72,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "B",
@ -105,6 +107,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "CONST",
@ -137,6 +140,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "CONST_WITH_INNER",
@ -169,6 +173,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Enum",
@ -203,6 +208,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "ItemLikeMacro",
@ -237,6 +243,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Macro",
@ -271,6 +278,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "STATIC",
@ -303,6 +311,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Struct",
@ -337,6 +346,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructFromMacro",
@ -371,6 +381,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInFn",
@ -407,6 +418,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInNamedConst",
@ -443,6 +455,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInUnnamedConst",
@ -477,6 +490,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructT",
@ -511,6 +525,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Trait",
@ -543,6 +558,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Trait",
@ -577,6 +593,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Union",
@ -611,6 +628,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "a_mod",
@ -643,6 +661,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "b_mod",
@ -675,6 +694,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "define_struct",
@ -709,6 +729,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "generic_impl_fn",
@ -743,6 +764,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "impl_fn",
@ -777,6 +799,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "macro_rules_macro",
@ -811,6 +834,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "main",
@ -843,6 +867,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "really_define_struct",
@ -877,6 +902,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "trait_fn",
@ -911,6 +937,7 @@
is_assoc: true,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
],
),
@ -954,6 +981,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
],
),
@ -995,6 +1023,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "IsThisJustATrait",
@ -1029,6 +1058,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "StructInModB",
@ -1063,6 +1093,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "SuperItemLikeMacro",
@ -1097,6 +1128,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "ThisStruct",
@ -1131,6 +1163,7 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
],
),

View file

@ -32,5 +32,6 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
]

View file

@ -32,6 +32,7 @@
is_assoc: false,
is_import: false,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
FileSymbol {
name: "Foo",
@ -66,5 +67,6 @@
is_assoc: false,
is_import: true,
do_not_complete: Yes,
_marker: PhantomData<&()>,
},
]

View file

@ -225,7 +225,7 @@ impl NavigationTarget {
}
}
impl TryToNav for FileSymbol {
impl<'db> TryToNav for FileSymbol<'db> {
fn try_to_nav(
&self,
sema: &Semantics<'_, RootDatabase>,