Skip to content

Don't recompute DisambiguatorState for every RPITIT in trait definition #143258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2460,13 +2460,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// type a projection.
let in_trait = match opaque_ty.origin {
hir::OpaqueTyOrigin::FnReturn {
parent,
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
parent,
in_trait_or_impl: Some(hir::RpitContext::Trait),
..
} => true,
} => Some(parent),
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
Expand All @@ -2475,7 +2477,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::TyAlias { .. } => false,
| hir::OpaqueTyOrigin::TyAlias { .. } => None,
};

self.lower_opaque_ty(opaque_ty.def_id, in_trait)
Expand Down Expand Up @@ -2595,17 +2597,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
#[instrument(level = "debug", skip(self), ret)]
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
let tcx = self.tcx();

let lifetimes = tcx.opaque_captured_lifetimes(def_id);
debug!(?lifetimes);

// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
// type a projection.
let def_id = if in_trait {
tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id()
// If this is an RPITIT and we are using the new RPITIT lowering scheme,
// do a linear search to map this to the synthetic associated type that
// it will be lowered to.
let def_id = if let Some(parent_def_id) = in_trait {
*tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id)
.iter()
.find(|rpitit| match tcx.opt_rpitit_info(**rpitit) {
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
opaque_def_id.expect_local() == def_id
}
_ => unreachable!(),
})
.unwrap()
} else {
def_id.to_def_id()
};
Expand All @@ -2628,7 +2638,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
});
debug!(?args);

if in_trait {
if in_trait.is_some() {
Ty::new_projection_from_args(tcx, def_id, args)
} else {
Ty::new_opaque(tcx, def_id, args)
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,13 +1092,6 @@ rustc_queries! {
separate_provide_extern
}

/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
/// associated item.
query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
cache_on_disk_if { true }
}

/// Given an `impl_id`, return the trait it implements along with some header information.
/// Return `None` if this is an inherent impl.
query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {
Expand Down
58 changes: 28 additions & 30 deletions compiler/rustc_ty_utils/src/assoc.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
Expand All @@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) {
associated_item_def_ids,
associated_items,
associated_types_for_impl_traits_in_associated_fn,
associated_type_for_impl_trait_in_trait,
impl_item_implementor_ids,
..*providers
};
Expand Down Expand Up @@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
container: ty::AssocItemContainer::Impl,
}
}
struct RPITVisitor {
rpits: FxIndexSet<LocalDefId>,
struct RPITVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
synthetics: Vec<LocalDefId>,
data: DefPathData,
disambiguator: DisambiguatorState,
}

impl<'tcx> Visitor<'tcx> for RPITVisitor {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let hir::TyKind::OpaqueDef(opaq) = ty.kind
&& self.rpits.insert(opaq.def_id)
{
for bound in opaq.bounds {
intravisit::walk_param_bound(self, bound);
}
}
intravisit::walk_ty(self, ty)
impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
self.synthetics.push(associated_type_for_impl_trait_in_trait(
self.tcx,
opaque.def_id,
self.data,
&mut self.disambiguator,
));
intravisit::walk_opaque_ty(self, opaque)
}
}

Expand All @@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn(

match tcx.def_kind(parent_def_id) {
DefKind::Trait => {
let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };

if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
let mut visitor = RPITVisitor {
tcx,
synthetics: vec![],
data,
disambiguator: DisambiguatorState::with(parent_def_id, data, 0),
};
visitor.visit_fn_ret_ty(output);

tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
}))
tcx.arena.alloc_from_iter(
visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
)
} else {
&[]
}
Expand All @@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn(
let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
return &[];
};

tcx.arena.alloc_from_iter(
tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
move |&trait_assoc_def_id| {
Expand All @@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn(
fn associated_type_for_impl_trait_in_trait(
tcx: TyCtxt<'_>,
opaque_ty_def_id: LocalDefId,
data: DefPathData,
disambiguator: &mut DisambiguatorState,
) -> LocalDefId {
let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
Expand All @@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait(
let trait_def_id = tcx.local_parent(fn_def_id);
assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);

// Collect all opaque types in return position for the method and use
// the index as the disambiguator to make an unique def path.
let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap());
let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap();

let span = tcx.def_span(opaque_ty_def_id);
// Also use the method name to create an unique def path.
let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
let trait_assoc_ty = tcx.at(span).create_def(
trait_def_id,
// No name because this is an anonymous associated type.
None,
DefKind::AssocTy,
Some(data),
&mut DisambiguatorState::with(trait_def_id, data, disambiguator),
disambiguator,
);

let local_def_id = trait_assoc_ty.def_id();
Expand Down
Loading