From 5295de1694c07fe47db112468a08098f930fcf53 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 Feb 2023 18:27:26 -0300 Subject: [PATCH 1/5] Add opt_rpitit_info query --- compiler/rustc_middle/src/hir/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 8 ++++++++ compiler/rustc_middle/src/ty/mod.rs | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index ad119c4e07306..c9da711e556f5 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -177,6 +177,7 @@ pub fn provide(providers: &mut Providers) { } }; providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); + providers.opt_rpitit_info = |_, _| None; providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; providers.expn_that_defined = |tcx, id| { let id = id.expect_local(); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b07540cf58c11..ea31f348eede3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1144,6 +1144,14 @@ rustc_queries! { separate_provide_extern } + /// The `opt_rpitit_info` query returns the pair of the def id of the function where the RPIT + /// is defined and the opaque def id if any. + query opt_rpitit_info(def_id: DefId) -> Option { + desc { |tcx| "opt_rpitit_info `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + feedable + } + /// Gets the span for the definition. query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5084bc9cec6c6..5df01b8abc3b2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2071,6 +2071,12 @@ pub enum ImplOverlapKind { Issue33140, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +pub enum ImplTraitInTraitData { + Trait { fn_def_id: DefId, opaque_def_id: DefId }, + Impl { fn_def_id: DefId }, +} + impl<'tcx> TyCtxt<'tcx> { pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> { self.typeck(self.hir().body_owner_def_id(body)) From e74f50ecc217a4848ce77bed7ba580fbed0edb6b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 Feb 2023 13:05:08 -0300 Subject: [PATCH 2/5] Add unstable option new_rpitit to be used for new RPITIT lowering system --- compiler/rustc_session/src/options.rs | 3 +++ tests/rustdoc-ui/z-help.stdout | 1 + 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4beac931632be..b466a3fcdee91 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1503,6 +1503,9 @@ options! { "what location details should be tracked when using caller_location, either \ `none`, or a comma separated list of location details, for which \ valid options are `file`, `line`, and `column` (default: `file,line,column`)"), + lower_impl_trait_in_trait_to_assoc_ty: bool = (false, parse_bool, [TRACKED], + "modify the lowering strategy for `impl Trait` in traits so that they are lowered to \ + generic associated types"), ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 6aa9785f44e33..79e6b94f1aca5 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -87,6 +87,7 @@ -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) + -Z lower-impl-trait-in-trait-to-assoc-ty=val -- modify the lowering strategy for `impl Trait` in traits so that they are lowered to generic associated types -Z ls=val -- list the symbols defined by a library crate (default: no) -Z macro-backtrace=val -- show macro backtraces (default: no) -Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no) From be72beca68512a81e4a7fba6d1a0d4955566abe4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 Feb 2023 18:29:33 -0300 Subject: [PATCH 3/5] Fix typo in docs --- compiler/rustc_ty_utils/src/assoc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index d4866b5dbdd49..4418819acff62 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -196,7 +196,7 @@ fn associated_item_for_impl_trait_in_trait( trait_assoc_ty.def_id() } -/// Given an `trait_assoc_def_id` that corresponds to a previously synthethized impl trait in trait +/// 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( From 811a1cabda19ea4d6c6636e43dc760a3fcc685fd Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 Feb 2023 13:05:37 -0300 Subject: [PATCH 4/5] Make associated_item_def_ids for traits use an unstable option to also return associated types for RPITITs --- compiler/rustc_middle/src/query/mod.rs | 11 +++ compiler/rustc_ty_utils/src/assoc.rs | 94 ++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ea31f348eede3..51feae3cf8a61 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -90,6 +90,7 @@ rustc_queries! { /// Definitions that were generated with no HIR, would be feeded to return `None`. query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option{ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) } + feedable } /// Gives access to the HIR node's parent for the HIR owner `key`. @@ -166,6 +167,7 @@ rustc_queries! { } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } query collect_return_position_impl_trait_in_trait_tys(key: DefId) @@ -222,6 +224,7 @@ rustc_queries! { arena_cache cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the @@ -264,6 +267,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -588,6 +592,7 @@ rustc_queries! { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Returns the inferred outlives predicates (e.g., for `struct @@ -596,6 +601,7 @@ rustc_queries! { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Maps from the `DefId` of a trait to the list of @@ -728,6 +734,7 @@ rustc_queries! { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Collects the associated items defined on a trait or impl. @@ -1142,6 +1149,7 @@ rustc_queries! { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } /// The `opt_rpitit_info` query returns the pair of the def id of the function where the RPIT @@ -1165,6 +1173,7 @@ rustc_queries! { desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } query lookup_stability(def_id: DefId) -> Option { @@ -1506,6 +1515,7 @@ rustc_queries! { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } query check_well_formed(key: hir::OwnerId) -> () { @@ -1703,6 +1713,7 @@ rustc_queries! { query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern + feedable } query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 4418819acff62..efbbfe6c24b56 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,7 +4,8 @@ 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, TyCtxt}; +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 { @@ -21,9 +22,37 @@ 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::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_) => tcx.arena.alloc_from_iter( impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), ), @@ -193,7 +222,62 @@ fn associated_item_for_impl_trait_in_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); - trait_assoc_ty.def_id() + + 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 From 73e2fe0494cd91565f2f836af59b2fa37ab3ebdd Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 28 Feb 2023 13:13:31 -0300 Subject: [PATCH 5/5] Properly implement should_encode_fn_impl_trait_in_trait using new unstable option --- compiler/rustc_metadata/src/rmeta/encoder.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 27490a09a3646..ccb07804b9661 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1101,9 +1101,18 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -// Return `false` to avoid encoding impl trait in trait, while we don't use the query. -fn should_encode_fn_impl_trait_in_trait<'tcx>(_tcx: TyCtxt<'tcx>, _def_id: DefId) -> bool { - false +// We only encode impl trait in trait when using `lower-impl-trait-in-trait-to-assoc-ty` unstable +// option. +fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty + && let Some(assoc_item) = tcx.opt_associated_item(def_id) + && assoc_item.container == ty::AssocItemContainer::TraitContainer + && assoc_item.kind == ty::AssocKind::Fn + { + true + } else { + false + } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> {