Skip to content

Commit

Permalink
Auto merge of #118725 - lcnr:normalizes-to-projection-split-3, r=BoxyUwU
Browse files Browse the repository at this point in the history
split `NormalizesTo` out of `Projection` 3

third attempt at #112658. Rebasing #116262 is very annoying, so I am doing it again from scratch. We should now be able to merge it without regressing anything as we handle occurs check failures involving aliases correctly since #117088.

see https://hackmd.io/ktEL8knTSYmtdfrMMnA-Hg

fixes rust-lang/trait-system-refactor-initiative#1

r? `@compiler-errors`
  • Loading branch information
bors committed Dec 8, 2023
2 parents d6fa38a + ac50f4b commit 21982a4
Show file tree
Hide file tree
Showing 39 changed files with 310 additions and 189 deletions.
12 changes: 2 additions & 10 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,19 +657,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::NormalizesTo(..)
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
// N.B., this predicate is created by breaking down a
// `ClosureType: FnFoo()` predicate, where
// `ClosureType` represents some `Closure`. It can't
// possibly be referring to the current closure,
// because we haven't produced the `Closure` for
// this closure yet; this is exactly why the other
// code is looking for a self type of an unresolved
// inference variable.
| ty::PredicateKind::Ambiguous
=> None,
| ty::PredicateKind::Ambiguous => None,
},
)
}
Expand Down
71 changes: 45 additions & 26 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{AliasRelationDirection, TyVar};
use rustc_middle::ty::{IntType, UintType};
use rustc_span::DUMMY_SP;

Expand Down Expand Up @@ -459,7 +460,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
ambient_variance,
)?;

self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
// Constrain `b_vid` to the generalized type `b_ty`.
if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() {
self.infcx.inner.borrow_mut().type_variables().equate(b_vid, b_ty_vid);
} else {
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
}

if needs_wf {
self.obligations.push(Obligation::new(
Expand All @@ -484,31 +490,46 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// cyclic type. We instead delay the unification in case
// the alias can be normalized to something which does not
// mention `?0`.

// FIXME(-Ztrait-solver=next): replace this with `AliasRelate`
let &ty::Alias(kind, data) = a_ty.kind() else {
bug!("generalization should only result in infer vars for aliases");
};
if !self.infcx.next_trait_solver() {
// The old solver only accepts projection predicates for associated types.
match kind {
ty::AliasKind::Projection => {}
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque => {
return Err(TypeError::CyclicTy(a_ty));
if self.infcx.next_trait_solver() {
let (lhs, rhs, direction) = match ambient_variance {
ty::Variance::Invariant => {
(a_ty.into(), b_ty.into(), AliasRelationDirection::Equate)
}
ty::Variance::Covariant => {
(a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype)
}
ty::Variance::Contravariant => {
(b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype)
}
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
};
self.obligations.push(Obligation::new(
self.tcx(),
self.trace.cause.clone(),
self.param_env,
ty::PredicateKind::AliasRelate(lhs, rhs, direction),
));
} else {
match a_ty.kind() {
&ty::Alias(ty::AliasKind::Projection, data) => {
// FIXME: This does not handle subtyping correctly, we could
// instead create a new inference variable for `a_ty`, emitting
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
self.obligations.push(Obligation::new(
self.tcx(),
self.trace.cause.clone(),
self.param_env,
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
))
}
// The old solver only accepts projection predicates for associated types.
ty::Alias(
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
_,
) => return Err(TypeError::CyclicTy(a_ty)),
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
}
}

// FIXME: This does not handle subtyping correctly, we should switch to
// alias-relate in the new solver and could instead create a new inference
// variable for `a_ty`, emitting `Projection(a_ty, a_infer)` and
// `a_infer <: b_ty`.
self.obligations.push(Obligation::new(
self.tcx(),
self.trace.cause.clone(),
self.param_env,
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
))
} else {
match ambient_variance {
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
Expand All @@ -519,9 +540,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
a_ty,
b_ty,
),
ty::Variance::Bivariant => {
unreachable!("no code should be generalizing bivariantly (currently)")
}
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
}?;
}

Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_infer/src/infer/type_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
/// Precondition: `vid` must not have been previously instantiated.
pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
let vid = self.root_var(vid);
debug_assert!(!ty.is_ty_var(), "instantiating ty var with var: {vid:?} {ty:?}");
debug_assert!(self.probe(vid).is_unknown());
debug_assert!(
self.eq_relations().probe_value(vid).is_unknown(),
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
vid,
ty,
"instantiating type variable `{vid:?}` twice: new-value = {ty:?}, old-value={:?}",
self.eq_relations().probe_value(vid)
);
self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty });
Expand Down
70 changes: 26 additions & 44 deletions compiler/rustc_infer/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
fn elaborate(&mut self, elaboratable: &O) {
let tcx = self.visited.tcx;

let bound_predicate = elaboratable.predicate().kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
// We only elaborate clauses.
let Some(clause) = elaboratable.predicate().as_clause() else {
return;
};

let bound_clause = clause.kind();
match bound_clause.skip_binder() {
ty::ClauseKind::Trait(data) => {
// Negative trait bounds do not imply any supertrait bounds
if data.polarity == ty::ImplPolarity::Negative {
return;
Expand All @@ -280,49 +285,16 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
elaboratable.child_with_derived_cause(
clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)),
span,
bound_predicate.rebind(data),
bound_clause.rebind(data),
index,
)
});
debug!(?data, ?obligations, "super_predicates");
self.extend_deduped(obligations);
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => {
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
ty::PredicateKind::ObjectSafe(..) => {
// Currently, we do not elaborate object-safe
// predicates.
}
ty::PredicateKind::Subtype(..) => {
// Currently, we do not "elaborate" predicates like `X <: Y`,
// though conceivably we might.
}
ty::PredicateKind::Coerce(..) => {
// Currently, we do not "elaborate" predicates like `X -> Y`,
// though conceivably we might.
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
// Nothing to elaborate in a projection predicate.
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
// Currently, we do not elaborate const-evaluatable
// predicates.
}
ty::PredicateKind::ConstEquate(..) => {
// Currently, we do not elaborate const-equate
// predicates.
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {
// Nothing to elaborate from `'a: 'b`.
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
ty_max,
r_min,
))) => {
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
// We know that `T: 'a` for some type `T`. We can
// often elaborate this. For example, if we know that
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
Expand Down Expand Up @@ -385,15 +357,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
}
})
.map(|clause| {
elaboratable.child(bound_predicate.rebind(clause).to_predicate(tcx))
elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx))
}),
);
}
ty::PredicateKind::Ambiguous => {}
ty::PredicateKind::AliasRelate(..) => {
// No
ty::ClauseKind::RegionOutlives(..) => {
// Nothing to elaborate from `'a: 'b`.
}
ty::ClauseKind::WellFormed(..) => {
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
ty::ClauseKind::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
ty::ClauseKind::ConstEvaluatable(..) => {
// Currently, we do not elaborate const-evaluatable
// predicates.
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => {
ty::ClauseKind::ConstArgHasType(..) => {
// Nothing to elaborate
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
type NormalizesTo = ty::NormalizesTo<'tcx>;
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
type CoercePredicate = ty::CoercePredicate<'tcx>;
type ClosureKind = ty::ClosureKind;
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ impl FlagComputation {
self.add_const(found);
}
ty::PredicateKind::Ambiguous => {}
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
self.add_alias_ty(alias);
self.add_term(term);
}
ty::PredicateKind::AliasRelate(t1, t2, _) => {
self.add_term(t1);
self.add_term(t2);
Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ impl<'tcx> Predicate<'tcx> {
pub fn allow_normalization(self) -> bool {
match self.kind().skip_binder() {
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
// `NormalizesTo` is only used in the new solver, so this shouldn't
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
PredicateKind::NormalizesTo(..) => false,
PredicateKind::Clause(ClauseKind::Trait(_))
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
Expand Down Expand Up @@ -1093,6 +1097,33 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
}
}

/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
/// proven by actually normalizing `alias`.
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct NormalizesTo<'tcx> {
pub alias: AliasTy<'tcx>,
pub term: Term<'tcx>,
}

impl<'tcx> NormalizesTo<'tcx> {
pub fn self_ty(self) -> Ty<'tcx> {
self.alias.self_ty()
}

pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> {
Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
}

pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
self.alias.trait_def_id(tcx)
}

pub fn def_id(self) -> DefId {
self.alias.def_id
}
}

pub trait ToPolyTraitRef<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}
Expand Down Expand Up @@ -1274,13 +1305,20 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
}
}

impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
PredicateKind::NormalizesTo(self).to_predicate(tcx)
}
}

impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
let predicate = self.kind();
match predicate.skip_binder() {
PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
PredicateKind::Clause(ClauseKind::Projection(..))
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
| PredicateKind::NormalizesTo(..)
| PredicateKind::AliasRelate(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
Expand All @@ -1300,6 +1338,7 @@ impl<'tcx> Predicate<'tcx> {
PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
PredicateKind::Clause(ClauseKind::Trait(..))
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
| PredicateKind::NormalizesTo(..)
| PredicateKind::AliasRelate(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2814,6 +2814,7 @@ define_print! {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
}
ty::PredicateKind::Ambiguous => p!("ambiguous"),
ty::PredicateKind::NormalizesTo(data) => p!(print(data)),
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
}
}
Expand Down Expand Up @@ -2945,6 +2946,12 @@ define_print_and_forward_display! {
p!(print(self.term))
}

ty::NormalizesTo<'tcx> {
p!(print(self.alias), " normalizes-to ");
cx.reset_type_limit();
p!(print(self.term))
}

ty::Term<'tcx> {
match self.unpack() {
ty::TermKind::Ty(ty) => p!(print(ty)),
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
}
}

impl<'tcx> fmt::Debug for ty::NormalizesTo<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term)
}
}

impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.kind())
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_smir/src/rustc_smir/convert/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> {
stable_mir::ty::PredicateKind::ConstEquate(a.stable(tables), b.stable(tables))
}
PredicateKind::Ambiguous => stable_mir::ty::PredicateKind::Ambiguous,
PredicateKind::NormalizesTo(_pred) => unimplemented!(),
PredicateKind::AliasRelate(a, b, alias_relation_direction) => {
stable_mir::ty::PredicateKind::AliasRelate(
a.unpack().stable(tables),
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_trait_selection/src/solve/alias_relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.add_goal(Goal::new(
self.tcx(),
param_env,
ty::ProjectionPredicate { projection_ty: alias, term },
ty::NormalizesTo { alias, term },
));
self.try_evaluate_added_goals()?;
Ok(Some(self.resolve_vars_if_possible(term)))
Expand All @@ -109,11 +109,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
opaque: ty::AliasTy<'tcx>,
term: ty::Term<'tcx>,
) -> QueryResult<'tcx> {
self.add_goal(Goal::new(
self.tcx(),
param_env,
ty::ProjectionPredicate { projection_ty: opaque, term },
));
self.add_goal(Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }));
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}

Expand Down
Loading

0 comments on commit 21982a4

Please sign in to comment.