From ebc45c8505c16f3ef3d84875e27728fb9dfe76bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 5 Mar 2024 15:55:04 +0000 Subject: [PATCH] Uplift some feeding out of associated_type_for_impl_trait_in_impl and into queries --- .../src/collect/generics_of.rs | 37 +++++++++++++++ .../rustc_hir_analysis/src/collect/type_of.rs | 39 +++++++++------ compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_ty_utils/src/assoc.rs | 47 ++----------------- .../in-trait/rpitit-cycle-in-generics-of.rs | 18 +++++++ 5 files changed, 85 insertions(+), 60 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9cc6c16c126..c86788db988 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -14,6 +14,43 @@ use rustc_span::Span; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; + // For an RPITIT, synthesize generics which are equal to the opaque's generics + // and parent fn's generics compressed into one list. + if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = + tcx.opt_rpitit_info(def_id.to_def_id()) + { + let trait_def_id = tcx.parent(fn_def_id); + let opaque_ty_generics = tcx.generics_of(opaque_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(); + + return ty::Generics { + parent: Some(trait_def_id), + parent_count, + params, + param_def_id_to_index, + has_self: opaque_ty_generics.has_self, + has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + host_effect_index: parent_generics.host_effect_index, + }; + } + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 417f0fceaa8..2217e5280a7 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -5,7 +5,7 @@ use rustc_hir::HirId; use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -350,22 +350,31 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - let assoc_item = tcx.associated_item(def_id); - return map[&assoc_item.trait_item_def_id.unwrap()]; - } - Err(_) => { - return ty::EarlyBinder::bind(Ty::new_error_with_message( - tcx, - DUMMY_SP, - "Could not collect return position impl trait in trait tys", - )); + match tcx.opt_rpitit_info(def_id.to_def_id()) { + Some(ty::ImplTraitInTraitData::Impl { fn_def_id }) => { + match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) { + Ok(map) => { + let assoc_item = tcx.associated_item(def_id); + return map[&assoc_item.trait_item_def_id.unwrap()]; + } + Err(_) => { + return ty::EarlyBinder::bind(Ty::new_error_with_message( + tcx, + DUMMY_SP, + "Could not collect return position impl trait in trait tys", + )); + } } } + // For an RPITIT in a trait, just return the corresponding opaque. + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + return ty::EarlyBinder::bind(Ty::new_opaque( + tcx, + opaque_def_id, + ty::GenericArgs::identity_for_item(tcx, opaque_def_id), + )); + } + None => {} } let hir_id = tcx.local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e87bc581e6e..7fb12c2dd4d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -835,7 +835,7 @@ rustc_queries! { /// creates and returns the associated items that correspond to each impl trait in return position /// of the implemented trait. query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] { - desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) } + desc { |tcx| "creating associated items for opaque types returned by `{}`", tcx.def_path_str(fn_def_id) } cache_on_disk_if { fn_def_id.is_local() } separate_provide_extern } @@ -843,7 +843,7 @@ rustc_queries! { /// 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| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } + 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 } } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index db37bec4b82..26d3370469a 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,7 +4,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, GenericArgs, ImplTraitInTraitData, Ty, TyCtxt}; +use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) { @@ -284,48 +284,8 @@ fn associated_type_for_impl_trait_in_trait( // Copy defaultness of the containing function. trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id)); - // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_opaque( - tcx, - opaque_ty_def_id.to_def_id(), - GenericArgs::identity_for_item(tcx, opaque_ty_def_id), - ))); - 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: opaque_ty_generics.has_self, - has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, - host_effect_index: parent_generics.host_effect_index, - } - }); - // There are no inferred outlives for the synthesized associated type. trait_assoc_ty.inferred_outlives_of(&[]); @@ -382,8 +342,9 @@ fn associated_type_for_impl_trait_in_impl( impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id)); // 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. + // FIXME: This may be detrimental to diagnostics, as we resolve the early-bound vars + // here to paramswhose parent are items in the trait. We could synthesize new params + // here, but it seems overkill. 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; diff --git a/tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs b/tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs new file mode 100644 index 00000000000..882497d1015 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs @@ -0,0 +1,18 @@ +//@ check-pass + +// Check that we don't hit a query cycle when: +// 1. Computing generics_of, which requires... +// 2. Calling resolve_bound_vars, which requires... +// 3. Calling associated_items, which requires... +// 4. Calling associated_type_for_impl_trait_in_trait, which requires... +// 5. Computing generics_of, which cycles. + +pub trait Foo<'a> { + type Assoc; + + fn demo(other: T) -> impl Foo<'a, Assoc = Self::Assoc> + where + T: Foo<'a, Assoc = ()>; +} + +fn main() {}