Rollup merge of #109462 - compiler-errors:alias-relate, r=BoxyUwU,lcnr
Make alias-eq have a relation direction (and rename it to alias-relate) Emitting an "alias-eq" is too strict in some situations, since we don't always want strict equality between a projection and rigid ty. Adds a relation direction. * I could probably just reuse this [`RelationDir`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/combine/enum.RelationDir.html) -- happy to uplift that struct into middle and use that instead, but I didn't feel compelled to... 🤷 * Some of the matching in `compute_alias_relate_goal` is a bit verbose -- I guess I could simplify it by using [`At::relate`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/at/struct.At.html#method.relate) and mapping the relation-dir to a variance. * Alternatively, I coulld simplify things by making more helper functions on `EvalCtxt` (e.g. `EvalCtxt::relate_with_direction(T, T)` that also does the nested goal registration). No preference. r? ```@lcnr``` cc ```@BoxyUwU``` though boxy can claim it if she wants NOTE: first commit is all the changes, the second is just renaming stuff
This commit is contained in:
commit
5d28853efe
@ -1335,7 +1335,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
|
||||
},
|
||||
ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(_, _, _)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
|
@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>(
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
|
@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
// N.B., this predicate is created by breaking down a
|
||||
|
@ -838,7 +838,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
});
|
||||
|
@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
|
||||
if self.tcx.trait_solver_next() =>
|
||||
{
|
||||
relation.register_type_equate_obligation(a, b);
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
@ -842,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
|
||||
ty::PredicateKind::AliasEq(a.into(), b.into())
|
||||
ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
|
||||
} else {
|
||||
ty::PredicateKind::ConstEquate(a, b)
|
||||
})]);
|
||||
}
|
||||
|
||||
/// Register an obligation that both types must be equal to each other.
|
||||
///
|
||||
/// If they aren't equal then the relation doesn't hold.
|
||||
fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
|
||||
/// Register an obligation that both types must be related to each other according to
|
||||
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
self.alias_relate_direction(),
|
||||
))]);
|
||||
}
|
||||
|
||||
/// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
|
||||
/// of the relation.
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
|
||||
}
|
||||
|
||||
fn int_unification_error<'tcx>(
|
||||
|
@ -210,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations)
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
@ -711,6 +711,34 @@ where
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.delegate.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
|
||||
}
|
||||
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
// a :> b is b <: a
|
||||
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
|
||||
b.into(),
|
||||
a.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
// FIXME(deferred_projection_equality): Implement this when we trigger it.
|
||||
// Probably just need to do nothing here.
|
||||
ty::Variance::Bivariant => unreachable!(),
|
||||
})]);
|
||||
}
|
||||
}
|
||||
|
||||
/// When we encounter a binder like `for<..> fn(..)`, we actually have
|
||||
|
@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>(
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
|
@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// completely change the normalization routine with the new solver.
|
||||
//
|
||||
// The new solver correctly handles projection equality so this hack
|
||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
|
||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
|
||||
// not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
|
||||
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
|
||||
return projection_ty.to_ty(self.tcx);
|
||||
|
@ -236,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
ty::AliasRelationDirection::Subtype
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> {
|
||||
// Nothing to elaborate
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
// No
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
|
||||
|
@ -1601,7 +1601,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
||||
// Ignore projections, as they can only be global
|
||||
// if the trait bound is global
|
||||
Clause(Clause::Projection(..)) |
|
||||
AliasEq(..) |
|
||||
AliasRelate(..) |
|
||||
// Ignore bounds that a user can't type
|
||||
WellFormed(..) |
|
||||
ObjectSafe(..) |
|
||||
|
@ -288,7 +288,7 @@ impl FlagComputation {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(t1, t2) => {
|
||||
ty::PredicateKind::AliasRelate(t1, t2, _) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
|
@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
| PredicateKind::Clause(Clause::TypeOutlives(_))
|
||||
| PredicateKind::Clause(Clause::Projection(_))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::ClosureKind(_, _, _)
|
||||
| PredicateKind::Subtype(_)
|
||||
@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> {
|
||||
/// This predicate requires two terms to be equal to eachother.
|
||||
///
|
||||
/// Only used for new solver
|
||||
AliasEq(Term<'tcx>, Term<'tcx>),
|
||||
AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, Debug)]
|
||||
pub enum AliasRelationDirection {
|
||||
Equate,
|
||||
Subtype,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AliasRelationDirection {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AliasRelationDirection::Equate => write!(f, " == "),
|
||||
AliasRelationDirection::Subtype => write!(f, " <: "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This function returns `None` for `AliasKind::Opaque`.
|
||||
/// This function returns the inner `AliasTy` if this term is a projection.
|
||||
///
|
||||
/// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
|
||||
/// deal with constants.
|
||||
pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
|
||||
pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
|
||||
match self.unpack() {
|
||||
TermKind::Ty(ty) => match ty.kind() {
|
||||
ty::Alias(kind, alias_ty) => match kind {
|
||||
@ -1206,7 +1222,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
@ -1227,7 +1243,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
@ -1249,7 +1265,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
|
@ -2847,7 +2847,7 @@ define_print_and_forward_display! {
|
||||
p!("the type `", print(ty), "` is found in the environment")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => p!("ambiguous"),
|
||||
ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
||||
write!(f, "TypeWellFormedFromEnv({:?})", ty)
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
|
||||
ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => {
|
||||
write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||
crate::ty::AssocItem,
|
||||
crate::ty::AssocKind,
|
||||
crate::ty::AliasKind,
|
||||
crate::ty::AliasRelationDirection,
|
||||
crate::ty::Placeholder<crate::ty::BoundRegionKind>,
|
||||
crate::ty::Placeholder<crate::ty::BoundTyKind>,
|
||||
crate::ty::ClosureKind,
|
||||
|
@ -180,7 +180,7 @@ where
|
||||
| ty::PredicateKind::ConstEquate(_, _)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(_)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate),
|
||||
| ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,9 +223,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(lhs, rhs) => {
|
||||
self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
|
||||
.compute_alias_relate_goal(Goal {
|
||||
param_env,
|
||||
predicate: (lhs, rhs, direction),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
|
||||
@ -457,6 +459,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||
pub(super) fn sub<T: ToTrace<'tcx>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
sub: T,
|
||||
sup: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.sub(DefineOpaqueTypes::No, sub, sup)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
debug!(?e, "failed to subtype");
|
||||
NoSolution
|
||||
})
|
||||
}
|
||||
|
||||
/// Equates two values returning the nested goals without adding them
|
||||
/// to the nested goals of the `EvalCtxt`.
|
||||
///
|
||||
|
@ -73,7 +73,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::AliasEq(_, _) => {
|
||||
ty::PredicateKind::AliasRelate(_, _, _) => {
|
||||
FulfillmentErrorCode::CodeProjectionError(
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
|
||||
@ -101,11 +100,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
// That won't actually reflect in the query response, so it seems moot.
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
} else {
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), goal.param_env)
|
||||
.sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
|
||||
self.add_goals(obligations.into_iter().map(|pred| pred.into()));
|
||||
self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
@ -156,55 +151,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn compute_alias_eq_goal(
|
||||
fn compute_alias_relate_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
// We may need to invert the alias relation direction if dealing an alias on the RHS.
|
||||
enum Invert {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
let evaluate_normalizes_to =
|
||||
|ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
|
||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||
let result = ecx.probe(|ecx| {
|
||||
let other = match direction {
|
||||
// This is purely an optimization.
|
||||
ty::AliasRelationDirection::Equate => other,
|
||||
|
||||
let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
|
||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||
let r = ecx.probe(|ecx| {
|
||||
ecx.add_goal(goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: alias,
|
||||
term: other,
|
||||
}),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
debug!("evaluate_normalizes_to(..) -> {:?}", r);
|
||||
r
|
||||
};
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
let fresh = ecx.next_term_infer_of_kind(other);
|
||||
let (sub, sup) = match invert {
|
||||
Invert::No => (fresh, other),
|
||||
Invert::Yes => (other, fresh),
|
||||
};
|
||||
ecx.sub(goal.param_env, sub, sup)?;
|
||||
fresh
|
||||
}
|
||||
};
|
||||
ecx.add_goal(goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: alias,
|
||||
term: other,
|
||||
}),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}");
|
||||
result
|
||||
};
|
||||
|
||||
if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
|
||||
let (lhs, rhs, direction) = goal.predicate;
|
||||
|
||||
if lhs.is_infer() || rhs.is_infer() {
|
||||
bug!(
|
||||
"`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
|
||||
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
|
||||
);
|
||||
}
|
||||
|
||||
match (
|
||||
goal.predicate.0.to_alias_term_no_opaque(tcx),
|
||||
goal.predicate.1.to_alias_term_no_opaque(tcx),
|
||||
) {
|
||||
(None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"),
|
||||
(Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1),
|
||||
(None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0),
|
||||
match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
|
||||
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
|
||||
|
||||
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
|
||||
(Some(alias_lhs), None) => {
|
||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
|
||||
}
|
||||
|
||||
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
|
||||
(None, Some(alias_rhs)) => {
|
||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
|
||||
}
|
||||
|
||||
(Some(alias_lhs), Some(alias_rhs)) => {
|
||||
debug!("compute_alias_eq_goal: both sides are aliases");
|
||||
debug!("compute_alias_relate_goal: both sides are aliases");
|
||||
|
||||
let mut candidates = Vec::with_capacity(3);
|
||||
let candidates = vec![
|
||||
// LHS normalizes-to RHS
|
||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No),
|
||||
// RHS normalizes-to RHS
|
||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes),
|
||||
// Relate via substs
|
||||
self.probe(|ecx| {
|
||||
debug!(
|
||||
"compute_alias_relate_goal: alias defids are equal, equating substs"
|
||||
);
|
||||
|
||||
// Evaluate all 3 potential candidates for the alias' being equal
|
||||
candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
|
||||
candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
|
||||
candidates.push(self.probe(|ecx| {
|
||||
debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
|
||||
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}));
|
||||
match direction {
|
||||
ty::AliasRelationDirection::Equate => {
|
||||
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
}
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
}
|
||||
}
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}),
|
||||
];
|
||||
debug!(?candidates);
|
||||
|
||||
self.try_merge_responses(candidates.into_iter())
|
||||
|
@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
// the `ParamEnv`.
|
||||
ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): We really should get rid of this relation.
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
|
||||
// FIXME(deferred_projection_equality)
|
||||
}
|
||||
|
@ -1276,9 +1276,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
"TypeWellFormedFromEnv predicate should only exist in the environment"
|
||||
),
|
||||
|
||||
ty::PredicateKind::AliasEq(..) => span_bug!(
|
||||
ty::PredicateKind::AliasRelate(..) => span_bug!(
|
||||
span,
|
||||
"AliasEq predicate should never be the predicate cause of a SelectionError"
|
||||
"AliasRelate predicate should never be the predicate cause of a SelectionError"
|
||||
),
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
|
||||
|
@ -361,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
bug!("AliasEq is only used for new solver")
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used for new solver")
|
||||
}
|
||||
},
|
||||
Some(pred) => match pred {
|
||||
@ -630,8 +630,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
bug!("AliasEq is only used for new solver")
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used for new solver")
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
|
||||
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
|
||||
|
@ -335,7 +335,7 @@ fn predicate_references_self<'tcx>(
|
||||
has_self_ty(&ty.into()).then_some(sp)
|
||||
}
|
||||
|
||||
ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
|
||||
ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
|
||||
|
||||
ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
@ -395,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
|
||||
}
|
||||
|
@ -977,8 +977,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
bug!("AliasEq is only used for new solver")
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used for new solver")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
|
||||
|
@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>(
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`")
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`")
|
||||
}
|
||||
}
|
||||
|
||||
@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>(
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
|
||||
ref t,
|
||||
|
@ -119,7 +119,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
|
||||
},
|
||||
ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
@ -215,7 +215,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
|
||||
// some of these in terms of chalk operations.
|
||||
ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
@ -652,7 +652,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
|
||||
|
||||
ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
@ -787,7 +787,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
@ -86,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
if obligation.predicate.has_non_region_infer() {
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::AliasEq(..) => {
|
||||
| ty::PredicateKind::AliasRelate(..) => {
|
||||
ocx.register_obligation(obligation.clone());
|
||||
}
|
||||
_ => {}
|
||||
@ -110,7 +110,7 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
|
||||
// We need to search through *all* WellFormed predicates
|
||||
|
@ -61,7 +61,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
|
@ -324,7 +324,7 @@ pub(crate) fn clean_predicate<'tcx>(
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
|
||||
|
||||
ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
|
@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
|
||||
ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"),
|
||||
ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
|
||||
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
|
||||
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
|
||||
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
|
||||
|
34
tests/ui/traits/new-solver/alias-sub.rs
Normal file
34
tests/ui/traits/new-solver/alias-sub.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
|
||||
trait Trait {
|
||||
type Assoc: Sized;
|
||||
}
|
||||
|
||||
impl Trait for &'static str {
|
||||
type Assoc = &'static str;
|
||||
}
|
||||
|
||||
// Wrapper is just here to get around stupid `Sized` obligations in mir typeck
|
||||
struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>);
|
||||
fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() }
|
||||
|
||||
|
||||
trait IsStaticStr {}
|
||||
impl IsStaticStr for (&'static str,) {}
|
||||
fn define<T: IsStaticStr>(_: T) {}
|
||||
|
||||
fn foo<'a, T: Trait>() {
|
||||
let y = Default::default();
|
||||
|
||||
// `<?0 as Trait>::Assoc <: &'a str`
|
||||
// In the old solver, this would *equate* the LHS and RHS.
|
||||
let _: Wrapper<&'a str> = mk(y);
|
||||
|
||||
// ... then later on, we constrain `?0 = &'static str`
|
||||
// but that should not mean that `'a = 'static`, because
|
||||
// we should use *sub* above.
|
||||
define((y,));
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user