Rollup merge of #122027 - compiler-errors:rpitit-cycle, r=spastorino
Uplift some feeding out of `associated_type_for_impl_trait_in_impl` and into queries This PR moves the `type_of` and `generics_of` query feeding out of `associated_type_for_impl_trait_in_impl`, since eagerly feeding results in query cycles due to a subtle interaction with `resolve_bound_vars`. Fixes #122019 r? spastorino
This commit is contained in:
commit
34cffae24c
5 changed files with 85 additions and 60 deletions
|
@ -14,6 +14,43 @@ use rustc_span::Span;
|
||||||
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
use rustc_hir::*;
|
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 hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||||
|
|
||||||
let node = tcx.hir_node(hir_id);
|
let node = tcx.hir_node(hir_id);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::HirId;
|
||||||
use rustc_middle::query::plumbing::CyclePlaceholder;
|
use rustc_middle::query::plumbing::CyclePlaceholder;
|
||||||
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
use rustc_middle::ty::print::with_forced_trimmed_paths;
|
||||||
use rustc_middle::ty::util::IntTypeExt;
|
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::symbol::Ident;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -350,22 +350,31 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||||
// If we are computing `type_of` the synthesized associated type for an RPITIT in the impl
|
// 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
|
// side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
|
||||||
// associated type in the impl.
|
// associated type in the impl.
|
||||||
if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) =
|
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||||
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) {
|
||||||
match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
|
Ok(map) => {
|
||||||
Ok(map) => {
|
let assoc_item = tcx.associated_item(def_id);
|
||||||
let assoc_item = tcx.associated_item(def_id);
|
return map[&assoc_item.trait_item_def_id.unwrap()];
|
||||||
return map[&assoc_item.trait_item_def_id.unwrap()];
|
}
|
||||||
}
|
Err(_) => {
|
||||||
Err(_) => {
|
return ty::EarlyBinder::bind(Ty::new_error_with_message(
|
||||||
return ty::EarlyBinder::bind(Ty::new_error_with_message(
|
tcx,
|
||||||
tcx,
|
DUMMY_SP,
|
||||||
DUMMY_SP,
|
"Could not collect return position impl trait in trait tys",
|
||||||
"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);
|
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||||
|
|
|
@ -826,7 +826,7 @@ rustc_queries! {
|
||||||
/// creates and returns the associated items that correspond to each impl trait in return position
|
/// creates and returns the associated items that correspond to each impl trait in return position
|
||||||
/// of the implemented trait.
|
/// of the implemented trait.
|
||||||
query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] {
|
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() }
|
cache_on_disk_if { fn_def_id.is_local() }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,7 @@ rustc_queries! {
|
||||||
/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
|
/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
|
||||||
/// associated item.
|
/// associated item.
|
||||||
query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
|
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 }
|
cache_on_disk_if { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_middle::query::Providers;
|
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;
|
use rustc_span::symbol::kw;
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
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.
|
// Copy defaultness of the containing function.
|
||||||
trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
|
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);
|
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.
|
// There are no inferred outlives for the synthesized associated type.
|
||||||
trait_assoc_ty.inferred_outlives_of(&[]);
|
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));
|
impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id));
|
||||||
|
|
||||||
// Copy generics_of the trait's associated item but the impl as the parent.
|
// 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
|
// FIXME: This may be detrimental to diagnostics, as we resolve the early-bound vars
|
||||||
// generics.
|
// here to paramswhose parent are items in the trait. We could synthesize new params
|
||||||
|
// here, but it seems overkill.
|
||||||
impl_assoc_ty.generics_of({
|
impl_assoc_ty.generics_of({
|
||||||
let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
|
let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
|
||||||
let trait_assoc_parent_count = trait_assoc_generics.parent_count;
|
let trait_assoc_parent_count = trait_assoc_generics.parent_count;
|
||||||
|
|
18
tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs
Normal file
18
tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs
Normal file
|
@ -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<T>(other: T) -> impl Foo<'a, Assoc = Self::Assoc>
|
||||||
|
where
|
||||||
|
T: Foo<'a, Assoc = ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Reference in a new issue