From 4f9fe856a25ab29345b90e7725509e9ee38a37be Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:41 +0200 Subject: Adding upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_ty_utils/src/assoc.rs | 270 +++++++++++++++++++++++++++++++++-- 1 file changed, 258 insertions(+), 12 deletions(-) (limited to 'compiler/rustc_ty_utils/src/assoc.rs') diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 424b52309..0648784b2 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,13 +1,19 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::DefPathData; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_middle::ty::{self, DefIdTree, ImplTraitInTraitData, InternalSubsts, TyCtxt}; +use rustc_span::symbol::kw; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { associated_item, associated_item_def_ids, associated_items, + associated_items_for_impl_trait_in_trait, + associated_item_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; @@ -16,20 +22,79 @@ pub fn provide(providers: &mut ty::query::Providers) { fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { let item = tcx.hir().expect_item(def_id.expect_local()); match item.kind { - hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( - trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), - ), - hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter( - impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), - ), - hir::ItemKind::TraitAlias(..) => &[], + hir::ItemKind::Trait(.., ref trait_item_refs) => { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + // We collect RPITITs for each trait method's return type and create a + // corresponding associated item using associated_items_for_impl_trait_in_trait + // query. + tcx.arena.alloc_from_iter( + trait_item_refs + .iter() + .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()) + .chain( + trait_item_refs + .iter() + .filter(|trait_item_ref| { + matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|trait_item_ref| { + let trait_fn_def_id = + trait_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id) + }) + .map(|def_id| *def_id), + ), + ) + } else { + tcx.arena.alloc_from_iter( + trait_item_refs + .iter() + .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), + ) + } + } + hir::ItemKind::Impl(ref impl_) => { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + // We collect RPITITs for each trait method's return type, on the impl side too and + // create a corresponding associated item using + // associated_items_for_impl_trait_in_trait query. + tcx.arena.alloc_from_iter( + impl_ + .items + .iter() + .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()) + .chain(impl_.of_trait.iter().flat_map(|_| { + impl_ + .items + .iter() + .filter(|impl_item_ref| { + matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|impl_item_ref| { + let impl_fn_def_id = + impl_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_items_for_impl_trait_in_trait(impl_fn_def_id) + }) + .map(|def_id| *def_id) + })), + ) + } else { + tcx.arena.alloc_from_iter( + impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), + ) + } + } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), } } -fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> { - let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); - ty::AssocItems::new(items) +fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems { + if tcx.is_trait_alias(def_id) { + ty::AssocItems::new(Vec::new()) + } else { + let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); + ty::AssocItems::new(items) + } } fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap { @@ -109,3 +174,184 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A fn_has_self_parameter: has_self, } } + +/// Given an `fn_def_id` of a trait or of an impl that implements a given trait: +/// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns +/// the associated items that correspond to each impl trait in return position for that trait. +/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it +/// creates and returns the associated items that correspond to each impl trait in return position +/// of the implemented trait. +fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -> &'_ [DefId] { + let parent_def_id = tcx.parent(fn_def_id); + + match tcx.def_kind(parent_def_id) { + DefKind::Trait => { + struct RPITVisitor { + rpits: Vec, + } + + impl<'v> Visitor<'v> for RPITVisitor { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind { + self.rpits.push(item_id.owner_id.def_id) + } + intravisit::walk_ty(self, ty) + } + } + + let mut visitor = RPITVisitor { rpits: Vec::new() }; + + if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) { + visitor.visit_fn_ret_ty(output); + + tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { + tcx.associated_item_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() + })) + } else { + &[] + } + } + + DefKind::Impl { .. } => { + 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_items_for_impl_trait_in_trait(trait_fn_def_id).iter().map( + move |trait_assoc_def_id| { + impl_associated_item_for_impl_trait_in_trait( + tcx, + trait_assoc_def_id.expect_local(), + fn_def_id.expect_local(), + ) + .to_def_id() + }, + ), + ) + } + + def_kind => bug!( + "associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}", + parent_def_id, + def_kind + ), + } +} + +/// Given an `opaque_ty_def_id` corresponding to an impl trait in trait, create and return the +/// corresponding associated item. +fn associated_item_for_impl_trait_in_trait( + tcx: TyCtxt<'_>, + opaque_ty_def_id: LocalDefId, +) -> LocalDefId { + let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id()); + let trait_def_id = tcx.parent(fn_def_id); + assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); + + let span = tcx.def_span(opaque_ty_def_id); + let trait_assoc_ty = + tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy); + + let local_def_id = trait_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + trait_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + + // There's no HIR associated with this new synthesized `def_id`, so feed + // `opt_local_def_id_to_hir_id` with `None`. + trait_assoc_ty.opt_local_def_id_to_hir_id(None); + + // Copy span of the opaque. + trait_assoc_ty.def_ident_span(Some(span)); + + // Add the def_id of the function and opaque that generated this synthesized associated type. + trait_assoc_ty.opt_rpitit_info(Some(ImplTraitInTraitData::Trait { + fn_def_id, + opaque_def_id: opaque_ty_def_id.to_def_id(), + })); + + trait_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: None, + container: ty::TraitContainer, + fn_has_self_parameter: false, + }); + + // Copy visility of the containing function. + trait_assoc_ty.visibility(tcx.visibility(fn_def_id)); + + // Copy impl_defaultness of the containing function. + trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); + + // Copy type_of of the opaque. + trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( + opaque_ty_def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()), + ))); + + // Copy generics_of of the opaque. + trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone()); + + // There are no predicates for the synthesized associated type. + trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { + parent: Some(trait_def_id), + predicates: &[], + }); + + // There are no inferred outlives for the synthesized associated type. + trait_assoc_ty.inferred_outlives_of(&[]); + + // FIXME implement this. + trait_assoc_ty.explicit_item_bounds(&[]); + + local_def_id +} + +/// Given an `trait_assoc_def_id` that corresponds to a previously synthesized impl trait in trait +/// into an associated type and an `impl_def_id` corresponding to an impl block, create and return +/// the corresponding associated item inside the impl block. +fn impl_associated_item_for_impl_trait_in_trait( + tcx: TyCtxt<'_>, + trait_assoc_def_id: LocalDefId, + impl_fn_def_id: LocalDefId, +) -> LocalDefId { + let impl_def_id = tcx.local_parent(impl_fn_def_id); + + // FIXME fix the span, we probably want the def_id of the return type of the function + let span = tcx.def_span(impl_fn_def_id); + let impl_assoc_ty = tcx.at(span).create_def(impl_def_id, DefPathData::ImplTraitAssocTy); + + let local_def_id = impl_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + impl_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + + // There's no HIR associated with this new synthesized `def_id`, so feed + // `opt_local_def_id_to_hir_id` with `None`. + impl_assoc_ty.opt_local_def_id_to_hir_id(None); + + // Add the def_id of the function that generated this synthesized associated type. + impl_assoc_ty.opt_rpitit_info(Some(ImplTraitInTraitData::Impl { + fn_def_id: impl_fn_def_id.to_def_id(), + })); + + impl_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: Some(trait_assoc_def_id.to_def_id()), + container: ty::ImplContainer, + fn_has_self_parameter: false, + }); + + // Copy impl_defaultness of the containing function. + impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id)); + + // Copy generics_of the trait's associated item. + // FIXME: This is not correct, in particular the parent is going to be wrong. So we would need + // to copy from trait_assoc_def_id and adjust things. + impl_assoc_ty.generics_of(tcx.generics_of(trait_assoc_def_id).clone()); + + local_def_id +} -- cgit v1.2.3