Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uplift some feeding out of associated_type_for_impl_trait_in_impl and into queries #122027

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
39 changes: 24 additions & 15 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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
// side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
// associated type in the impl.
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",
));
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);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,15 +835,15 @@ 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
}

/// 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 }
}

Expand Down
47 changes: 4 additions & 43 deletions compiler/rustc_ty_utils/src/assoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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(&[]);

Expand Down Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/impl-trait/in-trait/rpitit-cycle-in-generics-of.rs
Original file line number Diff line number Diff line change
@@ -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