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

Make RPITITs simple cases work when using lower_impl_trait_in_trait_to_assoc_ty #108700

Merged
merged 13 commits into from
Mar 12, 2023
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
10 changes: 9 additions & 1 deletion compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3049,10 +3049,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
&hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
let def_id = item_id.owner_id.to_def_id();

match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
let local_def_id = item_id.owner_id.def_id;
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
// type a projection.
let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() {
tcx.associated_item_for_impl_trait_in_trait(local_def_id).to_def_id()
} else {
local_def_id.to_def_id()
};
self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait)
}
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
Expand Down
23 changes: 15 additions & 8 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Projection, proj) = ty.kind()
&& self.interner().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder
&& self.interner().is_impl_trait_in_trait(proj.def_id)
{
if let Some((ty, _)) = self.types.get(&proj.def_id) {
return *ty;
Expand Down Expand Up @@ -1995,13 +1995,20 @@ pub(super) fn check_type_bounds<'tcx>(
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);

let impl_ty_span = match tcx.hir().get_by_def_id(impl_ty_def_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(_, Some(ty)),
..
}) => ty.span,
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span,
_ => bug!(),
// A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
// span for an impl's associated type. Instead, for these, use the def_span for the synthesized
// associated type.
let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() {
tcx.def_span(impl_ty_def_id)
} else {
match tcx.hir().get_by_def_id(impl_ty_def_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(_, Some(ty)),
..
}) => ty.span,
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span,
_ => bug!(),
}
};
let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);

Expand Down
34 changes: 23 additions & 11 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::astconv::AstConv;
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::Span;

Expand Down Expand Up @@ -58,17 +58,10 @@ fn opaque_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
opaque_def_id: DefId,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
item_ty: Ty<'tcx>,
span: Span,
in_trait: bool,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
ty::print::with_no_queries!({
let substs = InternalSubsts::identity_for_item(tcx, opaque_def_id);
let item_ty = if in_trait {
tcx.mk_projection(opaque_def_id, substs)
} else {
tcx.mk_opaque(opaque_def_id, substs)
};

let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found
Expand All @@ -83,7 +76,18 @@ pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> &'_ [(ty::Predicate<'_>, Span)] {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
// If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that
// generated the synthesized associate type.
let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
tcx.opt_rpitit_info(def_id)
{
Some(opaque_def_id)
} else {
None
};

let bounds_def_id = rpitit_info.unwrap_or(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local());
match tcx.hir().get(hir_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _),
Expand All @@ -94,7 +98,15 @@ pub(super) fn explicit_item_bounds(
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }),
span,
..
}) => opaque_type_bounds(tcx, def_id, bounds, *span, *in_trait),
}) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
let item_ty = if *in_trait || rpitit_info.is_some() {
tcx.mk_projection(def_id, substs)
} else {
tcx.mk_opaque(def_id, substs)
};
opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code feels a little tangled but I don't know how to disentangle it... 🤔

_ => bug!("item_bounds called on {:?}", def_id),
}
}
Expand Down
21 changes: 20 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{
self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
Expand Down Expand Up @@ -244,6 +245,24 @@ fn get_path_containing_arg_in_pat<'hir>(
}

pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> 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) {
spastorino marked this conversation as resolved.
Show resolved Hide resolved
match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
Ok(map) => {
let assoc_item = tcx.associated_item(def_id);
return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]);
}
Err(_) => {
return ty::EarlyBinder(tcx.ty_error_with_message(
DUMMY_SP,
"Could not collect return position impl trait in trait tys",
));
}
}
}

let def_id = def_id.expect_local();
use rustc_hir::*;

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
// 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
if tcx.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
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,7 @@ rustc_queries! {
/// might want to use `reveal_all()` method to change modes.
query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
feedable
}

/// Like `param_env`, but returns the `ParamEnv` in `Reveal::All` mode.
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,18 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn trait_solver_next(self) -> bool {
self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next
}

pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool {
self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty
}

pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
if self.lower_impl_trait_in_trait_to_assoc_ty() {
self.def_kind(def_id) == DefKind::AssocTy && self.opt_rpitit_info(def_id).is_some()
} else {
self.def_kind(def_id) == DefKind::ImplTraitPlaceholder
}
}
}

impl<'tcx> TyCtxtAt<'tcx> {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
continue;
}

// Avoid accessing the HIR for the synthesized associated type generated for RPITITs.
if self.tcx.opt_rpitit_info(id).is_some() {
spastorino marked this conversation as resolved.
Show resolved Hide resolved
self.live_symbols.insert(id);
continue;
}

// in the case of tuple struct constructors we want to check the item, not the generated
// tuple struct constructor function
let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
Expand Down
60 changes: 49 additions & 11 deletions compiler/rustc_ty_utils/src/assoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ 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) => {
if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty {
if tcx.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.
Expand Down Expand Up @@ -54,7 +54,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
}
}
hir::ItemKind::Impl(ref impl_) => {
if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty {
if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
// We collect RPITITs for each trait method's return type, on the impl side too and
// create a corresponding associated item using
// associated_items_for_impl_trait_in_trait query.
Expand Down Expand Up @@ -302,9 +302,6 @@ fn associated_item_for_impl_trait_in_trait(
// 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
}

Expand All @@ -316,11 +313,12 @@ fn impl_associated_item_for_impl_trait_in_trait(
trait_assoc_def_id: LocalDefId,
impl_fn_def_id: LocalDefId,
) -> LocalDefId {
let impl_def_id = tcx.local_parent(impl_fn_def_id);
let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
let impl_def_id = impl_local_def_id.to_def_id();

// FIXME fix the span, we probably want the def_id of the return type of the function
let span = tcx.def_span(impl_fn_def_id);
let impl_assoc_ty = tcx.at(span).create_def(impl_def_id, DefPathData::ImplTraitAssocTy);
let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy);

let local_def_id = impl_assoc_ty.def_id();
let def_id = local_def_id.to_def_id();
Expand All @@ -345,13 +343,53 @@ fn impl_associated_item_for_impl_trait_in_trait(
fn_has_self_parameter: false,
});

// Copy param_env of the containing function. The synthesized associated type doesn't have
// extra predicates to assume.
impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id));
spastorino marked this conversation as resolved.
Show resolved Hide resolved

// Copy impl_defaultness of the containing function.
impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id));

// Copy generics_of the trait's associated item.
// FIXME: This is not correct, in particular the parent is going to be wrong. So we would need
// to copy from trait_assoc_def_id and adjust things.
impl_assoc_ty.generics_of(tcx.generics_of(trait_assoc_def_id).clone());
// Copy generics_of the trait's associated item but the impl as the parent.
impl_assoc_ty.generics_of({
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
let trait_assoc_parent_count = trait_assoc_generics.parent_count;
let mut params = trait_assoc_generics.params.clone();

let parent_generics = tcx.generics_of(impl_def_id);
let parent_count = parent_generics.parent_count + parent_generics.params.len();

let mut impl_fn_params = tcx.generics_of(impl_fn_def_id).params.clone();

for param in &mut params {
param.index = param.index + parent_count as u32 + impl_fn_params.len() as u32
- trait_assoc_parent_count as u32;
}

impl_fn_params.extend(params);
params = impl_fn_params;

let param_def_id_to_index =
params.iter().map(|param| (param.def_id, param.index)).collect();

ty::Generics {
parent: Some(impl_def_id),
parent_count,
params,
param_def_id_to_index,
has_self: false,
has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
}
});

// There are no predicates for the synthesized associated type.
impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates {
parent: Some(impl_def_id),
predicates: &[],
});

// There are no inferred outlives for the synthesized associated type.
impl_assoc_ty.inferred_outlives_of(&[]);

local_def_id
}
13 changes: 11 additions & 2 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_middle::ty::{
self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
TypeSuperVisitable, TypeVisitable, TypeVisitor,
self, Binder, EarlyBinder, ImplTraitInTraitData, Predicate, PredicateKind, ToPredicate, Ty,
TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use rustc_session::config::TraitSolver;
use rustc_span::def_id::{DefId, CRATE_DEF_ID};
Expand Down Expand Up @@ -117,6 +117,15 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {

/// See `ParamEnv` struct definition for details.
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// When computing the param_env of an RPITIT, copy param_env of the containing function. The
// synthesized associated type doesn't have extra predicates to assume.
let def_id =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not being fed? Cycles?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all of the queries that I'm not feeding are because of cycles.
To be honest, I'm starting to think that feeding everything is ungreat :). Maybe just feeding opt_rpitit_info and inside each query deciding is better because in order to understand what a query does you just go to the query. With the feeding strategy, if you want to understand how generics_of works, there's code in the query and there's code in assoc.rs which feeds that query and makes it do something completely different.

if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
fn_def_id
} else {
def_id
};

// Compute the bounds on Self and the type parameters.
let ty::InstantiatedPredicates { mut predicates, .. } =
tcx.predicates_of(def_id).instantiate_identity(tcx);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// check-pass
// compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty

#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]

trait Foo {
fn foo() -> impl Sized;
}

impl Foo for String {
fn foo() -> i32 {
22
}
}

fn main() {}