1
Fork 0

Rollup merge of #105661 - lcnr:evaluate-new, r=compiler-errors

implement the skeleton of the updated trait solver

cc ```@rust-lang/initiative-trait-system-refactor```

This is mostly following the architecture discussed in the types team meetup.

After discussing the desired changes for the trait solver, we encountered cyclic dependencies between them. Most notably between changing evaluate to be canonical and returning inference constraints. We cannot canonicalize evaluate without returning inference constraints due to coinductive cycles. However, caching inference constraints also relies on canonicalization. Implementing both of these changes at once in-place is not feasible.

This somewhat closely mirrors the current `evaluate` implementation with the following notable differences:
- it moves `project` into the core solver, allowing us to correctly deal with coinductive projections (will be required for implied bounds, perfect derive)
- it changes trait solver overflow to be non-fatal (required to backcompat breakage from changes to the iteration order of nested goals, deferred projection equality, generally very useful)
- it returns inference constraints and canonicalizes inputs and outputs (required for a lot things, most notably merging fulfill and evaluate, and deferred projection equality)
- it is implemented to work with lazy normalization

A lot of things aren't yet implemented, but the remaining FIXMEs should all be fairly self-contained and parallelizable. If the architecture looks correct and is what we want here, I would like to quickly merge this and then split the work.

r? ```@compiler-errors``` / ```@rust-lang/types``` :3
This commit is contained in:
nils 2022-12-23 18:02:13 +01:00 committed by GitHub
commit fd5af8cc23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1538 additions and 87 deletions

View file

@ -300,6 +300,16 @@ impl<'tcx, V> Canonical<'tcx, V> {
let Canonical { max_universe, variables, value } = self;
Canonical { max_universe, variables, value: map_op(value) }
}
/// Allows you to map the `value` of a canonical while keeping the same set of
/// bound variables.
///
/// **WARNING:** This function is very easy to mis-use, hence the name! See
/// the comment of [Canonical::unchecked_map] for more details.
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
let Canonical { max_universe, variables, value: _ } = self;
Canonical { max_universe, variables, value }
}
}
pub type QueryOutlivesConstraint<'tcx> = (

View file

@ -96,7 +96,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
#[derive(Copy, Clone, Debug, HashStable)]
#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)]
pub struct NoSolution;
pub type Fallible<T> = Result<T, NoSolution>;

View file

@ -180,6 +180,7 @@ impl Iterator for Ancestors<'_> {
}
/// Information about the most specialized definition of an associated item.
#[derive(Debug)]
pub struct LeafDef {
/// The associated item described by this `LeafDef`.
pub item: ty::AssocItem,

View file

@ -535,6 +535,17 @@ impl<'tcx> Predicate<'tcx> {
self
}
#[instrument(level = "debug", skip(tcx), ret)]
pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
tcx.trait_is_coinductive(data.def_id())
}
ty::PredicateKind::WellFormed(_) => true,
_ => false,
}
}
/// Whether this projection can be soundly normalized.
///
/// Wf predicates must not be normalized, as normalization
@ -1018,6 +1029,24 @@ pub struct ProjectionPredicate<'tcx> {
pub term: Term<'tcx>,
}
impl<'tcx> ProjectionPredicate<'tcx> {
pub fn self_ty(self) -> Ty<'tcx> {
self.projection_ty.self_ty()
}
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> {
Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self }
}
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
self.projection_ty.trait_def_id(tcx)
}
pub fn def_id(self) -> DefId {
self.projection_ty.def_id
}
}
pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
impl<'tcx> PolyProjectionPredicate<'tcx> {
@ -1054,18 +1083,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
}
}
impl<'tcx> ProjectionPredicate<'tcx> {
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
Self {
projection_ty: tcx.mk_alias_ty(
self.projection_ty.def_id,
[self_ty.into()].into_iter().chain(self.projection_ty.substs.iter().skip(1)),
),
..self
}
}
}
pub trait ToPolyTraitRef<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}

View file

@ -1169,7 +1169,7 @@ pub struct AliasTy<'tcx> {
}
impl<'tcx> AliasTy<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
DefKind::ImplTraitPlaceholder => {
@ -1183,7 +1183,7 @@ impl<'tcx> AliasTy<'tcx> {
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
/// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
pub fn trait_ref_and_own_substs(
&self,
self,
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
debug_assert!(matches!(tcx.def_kind(self.def_id), DefKind::AssocTy | DefKind::AssocConst));
@ -1202,14 +1202,18 @@ impl<'tcx> AliasTy<'tcx> {
/// WARNING: This will drop the substs for generic associated types
/// consider calling [Self::trait_ref_and_own_substs] to get those
/// as well.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
tcx.mk_trait_ref(def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
}
pub fn self_ty(&self) -> Ty<'tcx> {
pub fn self_ty(self) -> Ty<'tcx> {
self.substs.type_at(0)
}
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
}
}
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]

View file

@ -577,6 +577,10 @@ impl<T> EarlyBinder<T> {
pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
EarlyBinder(value)
}
pub fn skip_binder(self) -> T {
self.0
}
}
impl<T> EarlyBinder<Option<T>> {