Turn transitive dependencies into a query

This commit is contained in:
Lukas Wirth 2025-11-22 22:04:42 +01:00
parent 782cda9969
commit 66b6a1e474
9 changed files with 44 additions and 45 deletions

View File

@ -460,6 +460,32 @@ pub struct Crate {
pub env: Env,
}
#[salsa::tracked]
impl Crate {
/// Returns an iterator over all transitive dependencies of the given crate,
/// including the crate itself.
///
/// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
#[salsa::tracked(returns(deref))]
pub fn transitive_deps(self, db: &dyn salsa::Database) -> Box<[Crate]> {
// There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible
// and removing that is a bit difficult.
let mut worklist = vec![self];
let mut deps_seen = FxHashSet::default();
let mut deps = Vec::new();
while let Some(krate) = worklist.pop() {
if !deps_seen.insert(krate) {
continue;
}
deps.push(krate);
worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id));
}
deps.into_boxed_slice()
}
}
/// The mapping from [`UniqueCrateData`] to their [`Crate`] input.
#[derive(Debug, Default)]
pub struct CratesMap(DashMap<UniqueCrateData, Crate, BuildHasherDefault<FxHasher>>);

View File

@ -257,13 +257,6 @@ pub trait RootQueryDb: SourceDatabase + salsa::Database {
#[salsa::input]
fn all_crates(&self) -> Arc<Box<[Crate]>>;
/// Returns an iterator over all transitive dependencies of the given crate,
/// including the crate itself.
///
/// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
#[salsa::transparent]
fn transitive_deps(&self, crate_id: Crate) -> FxHashSet<Crate>;
/// Returns all transitive reverse dependencies of the given crate,
/// including the crate itself.
///
@ -273,23 +266,6 @@ pub trait RootQueryDb: SourceDatabase + salsa::Database {
fn transitive_rev_deps(&self, of: Crate) -> FxHashSet<Crate>;
}
fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet<Crate> {
// There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible
// and removing that is a bit difficult.
let mut worklist = vec![crate_id];
let mut deps = FxHashSet::default();
while let Some(krate) = worklist.pop() {
if !deps.insert(krate) {
continue;
}
worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id));
}
deps
}
#[salsa_macros::db]
pub trait SourceDatabase: salsa::Database {
/// Text of the file.

View File

@ -273,10 +273,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
// endregion:visibilities
#[salsa::invoke(crate::lang_item::notable_traits_in_deps)]
fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>;
#[salsa::invoke(crate::lang_item::crate_notable_traits)]
fn crate_notable_traits(&self, krate: Crate) -> Option<Arc<[TraitId]>>;
#[salsa::transparent]
fn crate_notable_traits(&self, krate: Crate) -> Option<&[TraitId]>;
#[salsa::invoke(crate_supports_no_std)]
fn crate_supports_no_std(&self, crate_id: Crate) -> bool;

View File

@ -5,7 +5,6 @@
use hir_expand::name::Name;
use intern::{Symbol, sym};
use rustc_hash::FxHashMap;
use triomphe::Arc;
use crate::{
AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
@ -223,16 +222,8 @@ pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangIte
db.attrs(item).lang_item()
}
pub(crate) fn notable_traits_in_deps(db: &dyn DefDatabase, krate: Crate) -> Arc<[Arc<[TraitId]>]> {
let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered();
Arc::from_iter(
db.transitive_deps(krate).into_iter().filter_map(|krate| db.crate_notable_traits(krate)),
)
}
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Arc<[TraitId]>> {
let _p = tracing::info_span!("crate_notable_traits", ?krate).entered();
#[salsa::tracked(returns(as_deref))]
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
let mut traits = Vec::new();
let crate_def_map = crate_def_map(db, krate);

View File

@ -28,10 +28,10 @@ fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool {
};
let impls = match module.containing_block() {
Some(block) => match TraitImpls::for_block(db, block) {
Some(it) => it,
Some(it) => &**it,
None => return false,
},
None => &**TraitImpls::for_crate(db, module.krate()),
None => TraitImpls::for_crate(db, module.krate()),
};
!impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty()
}

View File

@ -687,7 +687,7 @@ impl TraitImpls {
#[salsa::tracked(returns(ref))]
pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
db.transitive_deps(krate).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
}
}

View File

@ -613,6 +613,7 @@ fn main() {
"impl_signature_with_source_map_shim",
"callable_item_signature_shim",
"TraitImpls::for_crate_and_deps_",
"Crate::transitive_deps_",
"TraitImpls::for_crate_",
"impl_trait_with_diagnostics_shim",
"impl_self_ty_with_diagnostics_shim",

View File

@ -250,6 +250,14 @@ impl Crate {
db.transitive_rev_deps(self.id).into_iter().map(|id| Crate { id })
}
pub fn notable_traits_in_deps(self, db: &dyn HirDatabase) -> impl Iterator<Item = &TraitId> {
self.id
.transitive_deps(db)
.into_iter()
.filter_map(|&krate| db.crate_notable_traits(krate))
.flatten()
}
pub fn root_module(self) -> Module {
Module { id: CrateRootModuleId::from(self.id).into() }
}

View File

@ -8,7 +8,6 @@ use std::{iter, ops::Not};
use either::Either;
use hir::{
DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics,
db::DefDatabase,
};
use ide_db::{
FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
@ -522,9 +521,8 @@ fn notable_traits<'db>(
return Vec::new();
}
db.notable_traits_in_deps(ty.krate(db).into())
.iter()
.flat_map(|it| &**it)
ty.krate(db)
.notable_traits_in_deps(db)
.filter_map(move |&trait_| {
let trait_ = trait_.into();
ty.impls_trait(db, trait_, &[]).then(|| {