Change:
Minimal example (): outputs In the example, the implementation is irrelevant. The definition itself is the cause for error. Removing either the lifetime or the results in successful compilation as expected. I don't understand why it's causing a cycle error, but intuitively I don't see why it should be. Introducing an trait with a blanket implementation is a possible workaround and what I'll be doing while the issue exists.

Discussion:
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; <ins> // 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, }; } </ins> let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id);

use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; <del> use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; </del> <ins> use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; </ins> use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP};

// If we are computing `type_of` the synthesized associated type for an RPITIT in the impl // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the // associated type in the impl. <del> if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id.to_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", )); </del> <ins> 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", )); } </ins> } } <ins> // 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 => {} </ins> } let hir_id = tcx.local_def_id_to_hir_id(def_id);

/// 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] { <del> desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) } </del> <ins> desc { |tcx| "creating associated items for opaque types returned by `{}`", tcx.def_path_str(fn_def_id) } </ins> cache_on_disk_if { fn_def_id.is_local() } separate_provide_extern }

/// 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 { <del> desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } </del> <ins> desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) } </ins> cache_on_disk_if { true } }

use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::query::Providers; <del> use rustc_middle::ty::{self, GenericArgs, ImplTraitInTraitData, Ty, TyCtxt}; </del> <ins> use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; </ins> use rustc_span::symbol::kw; pub(crate) fn provide(providers: &mut Providers) {

// Copy defaultness of the containing function. trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id)); <del> // 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), ))); </del> trait_assoc_ty.is_type_alias_impl_trait(false); <del> // 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, } }); </del> // There are no inferred outlives for the synthesized associated type. trait_assoc_ty.inferred_outlives_of(&[]);

impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id)); // Copy generics_of the trait's associated item but the impl as the parent. <del> // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl // generics. </del> <ins> // 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. </ins> 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;

<ins> //@ 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<T>(other: T) -> impl Foo<'a, Assoc = Self::Assoc> where T: Foo<'a, Assoc = ()>; } fn main() {} </ins>