summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ty_utils/src/assoc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ty_utils/src/assoc.rs')
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs270
1 files changed, 258 insertions, 12 deletions
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<DefId, DefId> {
@@ -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<LocalDefId>,
+ }
+
+ 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
+}