diff options
Diffstat (limited to 'compiler/rustc_ty_utils/src/assoc.rs')
-rw-r--r-- | compiler/rustc_ty_utils/src/assoc.rs | 245 |
1 files changed, 162 insertions, 83 deletions
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 0648784b2..de1e1a527 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,10 +1,10 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; -use rustc_middle::ty::{self, DefIdTree, ImplTraitInTraitData, InternalSubsts, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt}; use rustc_span::symbol::kw; pub fn provide(providers: &mut ty::query::Providers) { @@ -12,20 +12,20 @@ pub fn provide(providers: &mut 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, + associated_types_for_impl_traits_in_associated_fn, + associated_type_for_impl_trait_in_trait, impl_item_implementor_ids, ..*providers }; } -fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { - let item = tcx.hir().expect_item(def_id.expect_local()); +fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { + let item = tcx.hir().expect_item(def_id); match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => { - if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + if tcx.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 + // corresponding associated item using associated_types_for_impl_traits_in_associated_fn // query. tcx.arena.alloc_from_iter( trait_item_refs @@ -40,7 +40,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { .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) + tcx.associated_types_for_impl_traits_in_associated_fn( + trait_fn_def_id, + ) }) .map(|def_id| *def_id), ), @@ -54,10 +56,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { } } hir::ItemKind::Impl(ref impl_) => { - if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + if tcx.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. + // associated_types_for_impl_traits_in_associated_fn query. tcx.arena.alloc_from_iter( impl_ .items @@ -73,7 +75,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { .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) + tcx.associated_types_for_impl_traits_in_associated_fn( + impl_fn_def_id, + ) }) .map(|def_id| *def_id) })), @@ -97,34 +101,33 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems { } } -fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> { +fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> { tcx.associated_items(impl_id) .in_definition_order() .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id))) .collect() } -fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { - let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); +fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { + let id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(id); let parent_item = tcx.hir().expect_item(parent_def_id.def_id); match parent_item.kind { hir::ItemKind::Impl(ref impl_) => { - if let Some(impl_item_ref) = - impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_impl_item_ref(impl_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } hir::ItemKind::Trait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = - trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id) + trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id) { let assoc_item = associated_item_from_trait_item_ref(trait_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); + debug_assert_eq!(assoc_item.def_id.expect_local(), def_id); return assoc_item; } } @@ -154,6 +157,7 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty trait_item_def_id: Some(owner_id.to_def_id()), container: ty::TraitContainer, fn_has_self_parameter: has_self, + opt_rpitit_info: None, } } @@ -172,40 +176,53 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A trait_item_def_id: impl_item_ref.trait_item_def_id, container: ty::ImplContainer, fn_has_self_parameter: has_self, + opt_rpitit_info: None, } } -/// 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); +/// Given an `fn_def_id` of a trait or a trait implementation: +/// +/// if `fn_def_id` is a function defined inside a trait, then it synthesizes +/// a new def id corresponding to a new associated type for each return- +/// position `impl Trait` in the signature. +/// +/// if `fn_def_id` is a function inside of an impl, then for each synthetic +/// associated type generated for the corresponding trait function described +/// above, synthesize a corresponding associated type in the impl. +fn associated_types_for_impl_traits_in_associated_fn( + tcx: TyCtxt<'_>, + fn_def_id: LocalDefId, +) -> &'_ [DefId] { + let parent_def_id = tcx.local_parent(fn_def_id); match tcx.def_kind(parent_def_id) { DefKind::Trait => { - struct RPITVisitor { - rpits: Vec<LocalDefId>, + struct RPITVisitor<'tcx> { + rpits: FxIndexSet<LocalDefId>, + tcx: TyCtxt<'tcx>, } - 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) + impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind + && self.rpits.insert(item_id.owner_id.def_id) + { + let opaque_item = self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty(); + for bound in opaque_item.bounds { + intravisit::walk_param_bound(self, bound); + } } intravisit::walk_ty(self, ty) } } - let mut visitor = RPITVisitor { rpits: Vec::new() }; + let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() }; - if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) { + if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { 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() + tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() })) } else { &[] @@ -216,40 +233,40 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) - 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() + tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map( + move |&trait_assoc_def_id| { + associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id) + .to_def_id() }, ), ) } def_kind => bug!( - "associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}", + "associated_types_for_impl_traits_in_associated_fn: {:?} 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( +/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated +/// function from a trait, synthesize an associated type for that `impl Trait` +/// that inherits properties that we infer from the method and the opaque type. +fn associated_type_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); + let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = + tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin + else { + bug!("expected opaque for {opaque_ty_def_id:?}"); + }; + let trait_def_id = tcx.local_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 trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -263,12 +280,6 @@ fn associated_item_for_impl_trait_in_trait( // 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, @@ -276,6 +287,10 @@ fn associated_item_for_impl_trait_in_trait( trait_item_def_id: None, container: ty::TraitContainer, fn_has_self_parameter: false, + opt_rpitit_info: Some(ImplTraitInTraitData::Trait { + fn_def_id: fn_def_id.to_def_id(), + opaque_def_id: opaque_ty_def_id.to_def_id(), + }), }); // Copy visility of the containing function. @@ -287,40 +302,70 @@ fn associated_item_for_impl_trait_in_trait( // 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()), + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); - // Copy generics_of of the opaque. - trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone()); + trait_assoc_ty.is_type_alias_impl_trait(false); + + // Copy generics_of of the opaque type item but the trait is the parent. + trait_assoc_ty.generics_of({ + let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id); + let opaque_ty_parent_count = opaque_ty_generics.parent_count; + let mut params = opaque_ty_generics.params.clone(); + + let parent_generics = tcx.generics_of(trait_def_id); + let parent_count = parent_generics.parent_count + parent_generics.params.len(); + + let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone(); + + for param in &mut params { + param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32 + - opaque_ty_parent_count as u32; + } + + trait_fn_params.extend(params); + params = trait_fn_params; + + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + ty::Generics { + parent: Some(trait_def_id.to_def_id()), + parent_count, + params, + param_def_id_to_index, + has_self: false, + has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + } + }); // There are no predicates for the synthesized associated type. trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(trait_def_id), + parent: Some(trait_def_id.to_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( +/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized +/// from an `impl Trait` in an associated function from a trait, and an +/// `impl_fn_def_id` that represents an implementation of the associated function +/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait` +/// that inherits properties that we infer from the method and the associated type. +fn associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, - trait_assoc_def_id: LocalDefId, + trait_assoc_def_id: DefId, impl_fn_def_id: LocalDefId, ) -> LocalDefId { - let impl_def_id = tcx.local_parent(impl_fn_def_id); + let impl_local_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 impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -331,27 +376,61 @@ fn impl_associated_item_for_impl_trait_in_trait( // `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(), - })); + // Copy span of the opaque. + impl_assoc_ty.def_ident_span(Some(span)); 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()), + trait_item_def_id: Some(trait_assoc_def_id), container: ty::ImplContainer, fn_has_self_parameter: false, + opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); + // Copy visility of the containing function. + impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id)); + // 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()); + // Copy generics_of the trait's associated item but the impl as the parent. + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl + // generics. + impl_assoc_ty.generics_of({ + let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id); + let trait_assoc_parent_count = trait_assoc_generics.parent_count; + let mut params = trait_assoc_generics.params.clone(); + + let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id()); + let parent_count = parent_generics.parent_count + parent_generics.params.len(); + + for param in &mut params { + param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32; + } + + let param_def_id_to_index = + params.iter().map(|param| (param.def_id, param.index)).collect(); + + ty::Generics { + parent: Some(impl_local_def_id.to_def_id()), + parent_count, + params, + param_def_id_to_index, + has_self: false, + has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, + } + }); + + // There are no predicates for the synthesized associated type. + impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates { + parent: Some(impl_local_def_id.to_def_id()), + predicates: &[], + }); + + // There are no inferred outlives for the synthesized associated type. + impl_assoc_ty.inferred_outlives_of(&[]); local_def_id } |