1
Fork 0

Rollup merge of #108203 - compiler-errors:rpitit-fix-defaults-2, r=jackh726

Fix RPITITs in default trait methods (by assuming projection predicates in param-env)

Instead of having special projection logic that allows us to turn `ProjectionTy(RPITIT, [Self#0, ...])` into `OpaqueTy(RPITIT, [Self#0, ...])`, we can instead augment the param-env of default trait method bodies to assume these as projection predicates. This should allow us to only project where we're allowed to!

In order to make this work without introducing a bunch of cycle errors, we additionally tweak the `OpaqueTypeExpander` used by `ParamEnv::with_reveal_all_normalized` to not normalize the right-hand side of projection predicates. This should be fine, because if we use the projection predicate to normalize some other projection type, we'll continue to normalize the opaque that it gets projected to.

This also makes it possible to support default trait methods with RPITITs in an associated-type based RPITIT lowering strategy without too much extra effort.

Fixes #107002
Alternative to #108142
This commit is contained in:
Guillaume Gomez 2023-02-19 14:47:56 +01:00 committed by GitHub
commit d2aef58eb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 37 deletions

View file

@ -1,8 +1,12 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
#[cfg(not(bootstrap))]
use rustc_middle::ty::ir::TypeVisitable;
use rustc_middle::ty::{
self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
self, ir::TypeVisitor, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
TypeSuperVisitable,
};
use rustc_session::config::TraitSolver;
use rustc_span::def_id::{DefId, CRATE_DEF_ID};
@ -136,6 +140,19 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
predicates.extend(environment);
}
if tcx.def_kind(def_id) == DefKind::AssocFn
&& tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer
{
let sig = tcx.fn_sig(def_id).subst_identity();
sig.visit_with(&mut ImplTraitInTraitFinder {
tcx,
fn_def_id: def_id,
bound_vars: sig.bound_vars(),
predicates: &mut predicates,
seen: FxHashSet::default(),
});
}
let local_did = def_id.as_local();
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
@ -222,6 +239,46 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
}
/// Walk through a function type, gathering all RPITITs and installing a
/// `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` predicate into the
/// predicates list. This allows us to observe that an RPITIT projects to
/// its corresponding opaque within the body of a default-body trait method.
struct ImplTraitInTraitFinder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
predicates: &'a mut Vec<Predicate<'tcx>>,
fn_def_id: DefId,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
seen: FxHashSet<DefId>,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
&& self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
&& self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id
&& self.seen.insert(alias_ty.def_id)
{
self.predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: alias_ty,
term: self.tcx.mk_alias(ty::Opaque, alias_ty).into(),
},
self.bound_vars,
)
.to_predicate(self.tcx),
);
for bound in self.tcx.item_bounds(alias_ty.def_id).subst_iter(self.tcx, alias_ty.substs)
{
bound.visit_with(self);
}
}
ty.super_visit_with(self)
}
}
/// Elaborate the environment.
///
/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s