1
Fork 0

Auto merge of #139018 - oli-obk:incremental-trait-impls, r=compiler-errors

Various local trait item iteration cleanups

Adding a trait impl for `Foo` unconditionally affected all queries that are interested in a completely independent trait `Bar`. Perf has no effect on this. We probably don't have a good perf test for this tho.

r? `@compiler-errors`

I am unsure about https://github.com/rust-lang/rust/pull/139018/commits/9d05efb66f7b599eeacb5d2456f844fe4768e865 as it doesn't improve anything wrt incremental, because we still do all the checks for valid `Drop` impls, which subsequently will still invoke many queries and basically keep the depgraph the same.

I want to do

9549077a47/compiler/rustc_middle/src/ty/trait_def.rs (L141)

but would leave that to a follow-up PR, this one changes enough things as it is
This commit is contained in:
bors 2025-04-02 10:10:50 +00:00
commit ae9173d7dd
26 changed files with 96 additions and 93 deletions

View file

@ -367,10 +367,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
pub fn hir_trait_impls(self, trait_did: DefId) -> &'tcx [LocalDefId] {
self.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
}
/// Gets the attributes on the crate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.

View file

@ -238,6 +238,8 @@ pub fn provide(providers: &mut Providers) {
}
};
providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
providers.local_trait_impls =
|tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]);
providers.expn_that_defined =
|tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
providers.in_scope_traits_map = |tcx, id| {

View file

@ -1502,6 +1502,11 @@ rustc_queries! {
desc { "finding local trait impls" }
}
/// Return all `impl` blocks of the given trait in the current crate.
query local_trait_impls(trait_id: DefId) -> &'tcx [LocalDefId] {
desc { "finding local trait impls of `{}`", tcx.def_path_str(trait_id) }
}
/// Given a trait `trait_id`, return all known `impl` blocks.
query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls {
arena_cache

View file

@ -236,7 +236,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
}
fn destructor(self, tcx: TyCtxt<'tcx>) -> Option<AdtDestructorKind> {
Some(match self.destructor(tcx)?.constness {
Some(match tcx.constness(self.destructor(tcx)?.did) {
hir::Constness::Const => AdtDestructorKind::Const,
hir::Constness::NotConst => AdtDestructorKind::NotConst,
})

View file

@ -1119,8 +1119,6 @@ pub struct PseudoCanonicalInput<'tcx, T> {
pub struct Destructor {
/// The `DefId` of the destructor method
pub did: DefId,
/// The constness of the destructor method
pub constness: hir::Constness,
}
// FIXME: consider combining this definition with regular `Destructor`

View file

@ -65,9 +65,11 @@ trivially_parameterized_over_tcx! {
crate::middle::lib_features::FeatureStability,
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
ty::AsyncDestructor,
ty::AssocItemContainer,
ty::Asyncness,
ty::DeducedParamAttrs,
ty::Destructor,
ty::Generics,
ty::ImplPolarity,
ty::ImplTraitInTraitData,

View file

@ -129,21 +129,6 @@ impl<'tcx> TraitDef {
}
impl<'tcx> TyCtxt<'tcx> {
/// `trait_def_id` MUST BE the `DefId` of a trait.
pub fn for_each_impl<F: FnMut(DefId)>(self, trait_def_id: DefId, mut f: F) {
let impls = self.trait_impls_of(trait_def_id);
for &impl_def_id in impls.blanket_impls.iter() {
f(impl_def_id);
}
for v in impls.non_blanket_impls.values() {
for &impl_def_id in v {
f(impl_def_id);
}
}
}
/// Iterate over every impl that could possibly match the self type `self_ty`.
///
/// `trait_def_id` MUST BE the `DefId` of a trait.
@ -235,7 +220,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
}
}
for &impl_def_id in tcx.hir_trait_impls(trait_id) {
for &impl_def_id in tcx.local_trait_impls(trait_id) {
let impl_def_id = impl_def_id.to_def_id();
let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();

View file

@ -389,55 +389,65 @@ impl<'tcx> TyCtxt<'tcx> {
/// Calculate the destructor of a given type.
pub fn calculate_dtor(
self,
adt_did: DefId,
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
adt_did: LocalDefId,
validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::Destructor> {
let drop_trait = self.lang_items().drop_trait()?;
self.ensure_ok().coherent_trait(drop_trait).ok()?;
let ty = self.type_of(adt_did).instantiate_identity();
let mut dtor_candidate = None;
self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
// `Drop` impls can only be written in the same crate as the adt, and cannot be blanket impls
for &impl_did in self.local_trait_impls(drop_trait) {
let Some(adt_def) = self.type_of(impl_did).skip_binder().ty_adt_def() else { continue };
if adt_def.did() != adt_did.to_def_id() {
continue;
}
if validate(self, impl_did).is_err() {
// Already `ErrorGuaranteed`, no need to delay a span bug here.
return;
continue;
}
let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
self.dcx()
.span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function");
return;
continue;
};
if let Some((old_item_id, _)) = dtor_candidate {
if let Some(old_item_id) = dtor_candidate {
self.dcx()
.struct_span_err(self.def_span(item_id), "multiple drop impls found")
.with_span_note(self.def_span(old_item_id), "other impl here")
.delay_as_bug();
}
dtor_candidate = Some((*item_id, self.impl_trait_header(impl_did).unwrap().constness));
});
dtor_candidate = Some(*item_id);
}
let (did, constness) = dtor_candidate?;
Some(ty::Destructor { did, constness })
let did = dtor_candidate?;
Some(ty::Destructor { did })
}
/// Calculate the async destructor of a given type.
pub fn calculate_async_dtor(
self,
adt_did: DefId,
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
adt_did: LocalDefId,
validate: impl Fn(Self, LocalDefId) -> Result<(), ErrorGuaranteed>,
) -> Option<ty::AsyncDestructor> {
let async_drop_trait = self.lang_items().async_drop_trait()?;
self.ensure_ok().coherent_trait(async_drop_trait).ok()?;
let ty = self.type_of(adt_did).instantiate_identity();
let mut dtor_candidate = None;
self.for_each_relevant_impl(async_drop_trait, ty, |impl_did| {
// `AsyncDrop` impls can only be written in the same crate as the adt, and cannot be blanket impls
for &impl_did in self.local_trait_impls(async_drop_trait) {
let Some(adt_def) = self.type_of(impl_did).skip_binder().ty_adt_def() else { continue };
if adt_def.did() != adt_did.to_def_id() {
continue;
}
if validate(self, impl_did).is_err() {
// Already `ErrorGuaranteed`, no need to delay a span bug here.
return;
continue;
}
let [future, ctor] = self.associated_item_def_ids(impl_did) else {
@ -445,7 +455,7 @@ impl<'tcx> TyCtxt<'tcx> {
self.def_span(impl_did),
"AsyncDrop impl without async_drop function or Dropper type",
);
return;
continue;
};
if let Some((_, _, old_impl_did)) = dtor_candidate {
@ -456,7 +466,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
dtor_candidate = Some((*future, *ctor, impl_did));
});
}
let (future, ctor, _) = dtor_candidate?;
Some(ty::AsyncDestructor { future, ctor })