mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
Auto merge of #107507 - BoxyUwU:deferred_projection_equality, r=lcnr
Implement `deferred_projection_equality` for erica solver Somewhat of a revival of #96912. When relating projections now emit an `AliasEq` obligation instead of attempting to determine equality of projections that may not be as normalized as possible (i.e. because of lazy norm, or just containing inference variables that prevent us from resolving an impl). Only do this when the new solver is enabled
This commit is contained in:
commit
1623ab0246
@ -1,4 +1,4 @@
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
@ -140,10 +140,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
||||
);
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -1320,6 +1320,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
ty::Clause::RegionOutlives(_) => bug!(),
|
||||
},
|
||||
ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(_, _, _)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
|
@ -517,6 +517,7 @@ fn trait_predicate_kind<'tcx>(
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
|
@ -55,6 +55,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
@ -669,6 +669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
// N.B., this predicate is created by breaking down a
|
||||
|
@ -837,6 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
|
||||
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
|
||||
};
|
||||
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
|
||||
use crate::traits::query::{Fallible, NoSolution};
|
||||
@ -717,10 +717,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{
|
||||
self, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
|
||||
TypeVisitable,
|
||||
self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -74,7 +74,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
b: Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>>
|
||||
where
|
||||
R: TypeRelation<'tcx>,
|
||||
R: ObligationEmittingRelation<'tcx>,
|
||||
{
|
||||
let a_is_expected = relation.a_is_expected();
|
||||
|
||||
@ -122,6 +122,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
|
||||
}
|
||||
|
||||
(ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
|
||||
relation.register_type_equate_obligation(a.into(), b.into());
|
||||
Ok(b)
|
||||
}
|
||||
(_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
|
||||
relation.register_type_equate_obligation(b.into(), a.into());
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
_ => ty::relate::super_relate_tys(relation, a, b),
|
||||
}
|
||||
}
|
||||
@ -133,7 +142,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>>
|
||||
where
|
||||
R: ConstEquateRelation<'tcx>,
|
||||
R: ObligationEmittingRelation<'tcx>,
|
||||
{
|
||||
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
|
||||
if a == b {
|
||||
@ -169,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// FIXME(#59490): Need to remove the leak check to accommodate
|
||||
// escaping bound variables here.
|
||||
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
|
||||
relation.const_equate_obligation(a, b);
|
||||
relation.register_const_equate_obligation(a, b);
|
||||
}
|
||||
return Ok(b);
|
||||
}
|
||||
@ -177,7 +186,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// FIXME(#59490): Need to remove the leak check to accommodate
|
||||
// escaping bound variables here.
|
||||
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
|
||||
relation.const_equate_obligation(a, b);
|
||||
relation.register_const_equate_obligation(a, b);
|
||||
}
|
||||
return Ok(a);
|
||||
}
|
||||
@ -435,32 +444,21 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||
Ok(Generalization { ty, needs_wf })
|
||||
}
|
||||
|
||||
pub fn add_const_equate_obligation(
|
||||
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.obligations.extend(obligations.into_iter());
|
||||
}
|
||||
|
||||
pub fn register_predicates(
|
||||
&mut self,
|
||||
a_is_expected: bool,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
|
||||
) {
|
||||
let predicate = if a_is_expected {
|
||||
ty::PredicateKind::ConstEquate(a, b)
|
||||
} else {
|
||||
ty::PredicateKind::ConstEquate(b, a)
|
||||
};
|
||||
self.obligations.push(Obligation::new(
|
||||
self.tcx(),
|
||||
self.trace.cause.clone(),
|
||||
self.param_env,
|
||||
ty::Binder::dummy(predicate),
|
||||
));
|
||||
self.obligations.extend(obligations.into_iter().map(|to_pred| {
|
||||
Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn mark_ambiguous(&mut self) {
|
||||
self.obligations.push(Obligation::new(
|
||||
self.tcx(),
|
||||
self.trace.cause.clone(),
|
||||
self.param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Ambiguous),
|
||||
));
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -779,11 +777,42 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
|
||||
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
||||
/// Register obligations that must hold in order for this relation to hold
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
|
||||
|
||||
/// Register predicates that must hold in order for this relation to hold. Uses
|
||||
/// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
|
||||
/// be used if control over the obligaton causes is required.
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
|
||||
);
|
||||
|
||||
/// Register an obligation that both constants must be equal to each other.
|
||||
///
|
||||
/// If they aren't equal then the relation doesn't hold.
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
|
||||
fn register_const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'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())
|
||||
} 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(
|
||||
a.into(),
|
||||
b.into(),
|
||||
))]);
|
||||
}
|
||||
}
|
||||
|
||||
fn int_unification_error<'tcx>(
|
||||
|
@ -1,4 +1,6 @@
|
||||
use super::combine::{CombineFields, ConstEquateRelation, RelationDir};
|
||||
use crate::traits::PredicateObligations;
|
||||
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
|
||||
use super::Subtype;
|
||||
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
@ -198,8 +200,15 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
self.fields.register_predicates(obligations);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! Greatest lower bound. See [`lattice`].
|
||||
|
||||
use super::combine::CombineFields;
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::InferCtxt;
|
||||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use crate::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
@ -136,10 +135,6 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
||||
&self.fields.trace.cause
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
|
||||
self.fields.obligations.extend(obligations)
|
||||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(v, a)?;
|
||||
@ -152,8 +147,15 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
self.fields.register_predicates(obligations);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,12 @@
|
||||
//!
|
||||
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
|
||||
|
||||
use super::combine::ObligationEmittingRelation;
|
||||
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use super::InferCtxt;
|
||||
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use crate::traits::ObligationCause;
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::TyVar;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
@ -30,13 +31,11 @@ use rustc_middle::ty::{self, Ty};
|
||||
///
|
||||
/// GLB moves "down" the lattice (to smaller values); LUB moves
|
||||
/// "up" the lattice (to bigger values).
|
||||
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
|
||||
pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
|
||||
fn infcx(&self) -> &'f InferCtxt<'tcx>;
|
||||
|
||||
fn cause(&self) -> &ObligationCause<'tcx>;
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
|
||||
|
||||
fn define_opaque_types(&self) -> bool;
|
||||
|
||||
// Relates the type `v` to `a` and `b` such that `v` represents
|
||||
@ -113,7 +112,7 @@ where
|
||||
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
|
||||
if this.define_opaque_types() && def_id.is_local() =>
|
||||
{
|
||||
this.add_obligations(
|
||||
this.register_obligations(
|
||||
infcx
|
||||
.handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
|
||||
.obligations,
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! Least upper bound. See [`lattice`].
|
||||
|
||||
use super::combine::CombineFields;
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::lattice::{self, LatticeDir};
|
||||
use super::InferCtxt;
|
||||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use crate::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
@ -127,12 +126,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
||||
fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
|
||||
self.fields.infcx
|
||||
@ -142,10 +135,6 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
|
||||
&self.fields.trace.cause
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
|
||||
self.fields.obligations.extend(obligations)
|
||||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(a, v)?;
|
||||
@ -157,3 +146,16 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
|
||||
self.fields.define_opaque_types
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
self.fields.register_predicates(obligations);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations)
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ pub use self::LateBoundRegionConversionTime::*;
|
||||
pub use self::RegionVariableOrigin::*;
|
||||
pub use self::SubregionOrigin::*;
|
||||
pub use self::ValuePairs::*;
|
||||
pub use combine::ObligationEmittingRelation;
|
||||
|
||||
use self::opaque_types::OpaqueTypeStorage;
|
||||
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
|
||||
|
@ -21,11 +21,10 @@
|
||||
//! thing we relate in chalk are basically domain goals and their
|
||||
//! constituents)
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::{Obligation, PredicateObligation};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
@ -36,11 +35,7 @@ use rustc_span::Span;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum NormalizationStrategy {
|
||||
Lazy,
|
||||
Eager,
|
||||
}
|
||||
use super::combine::ObligationEmittingRelation;
|
||||
|
||||
pub struct TypeRelating<'me, 'tcx, D>
|
||||
where
|
||||
@ -92,7 +87,7 @@ pub trait TypeRelatingDelegate<'tcx> {
|
||||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
);
|
||||
|
||||
fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex;
|
||||
@ -125,9 +120,6 @@ pub trait TypeRelatingDelegate<'tcx> {
|
||||
/// relation stating that `'?0: 'a`).
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
||||
|
||||
/// Define the normalization strategy to use, eager or lazy.
|
||||
fn normalization() -> NormalizationStrategy;
|
||||
|
||||
/// Enables some optimizations if we do not expect inference variables
|
||||
/// in the RHS of the relation.
|
||||
fn forbid_inference_vars() -> bool;
|
||||
@ -265,38 +257,6 @@ where
|
||||
self.delegate.push_outlives(sup, sub, info);
|
||||
}
|
||||
|
||||
/// Relate a projection type and some value type lazily. This will always
|
||||
/// succeed, but we push an additional `ProjectionEq` goal depending
|
||||
/// on the value type:
|
||||
/// - if the value type is any type `T` which is not a projection, we push
|
||||
/// `ProjectionEq(projection = T)`.
|
||||
/// - if the value type is another projection `other_projection`, we create
|
||||
/// a new inference variable `?U` and push the two goals
|
||||
/// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`.
|
||||
fn relate_projection_ty(
|
||||
&mut self,
|
||||
projection_ty: ty::AliasTy<'tcx>,
|
||||
value_ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
match *value_ty.kind() {
|
||||
ty::Alias(ty::Projection, other_projection_ty) => {
|
||||
let var = self.infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
// FIXME(lazy-normalization): This will always ICE, because the recursive
|
||||
// call will end up in the _ arm below.
|
||||
self.relate_projection_ty(projection_ty, var);
|
||||
self.relate_projection_ty(other_projection_ty, var);
|
||||
var
|
||||
}
|
||||
|
||||
_ => bug!("should never be invoked with eager normalization"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Relate a type inference variable with a value type. This works
|
||||
/// by creating a "generalization" G of the value where all the
|
||||
/// lifetimes are replaced with fresh inference values. This
|
||||
@ -335,12 +295,6 @@ where
|
||||
return Ok(value_ty);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection, projection_ty)
|
||||
if D::normalization() == NormalizationStrategy::Lazy =>
|
||||
{
|
||||
return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -627,18 +581,6 @@ where
|
||||
self.relate_opaques(a, b)
|
||||
}
|
||||
|
||||
(&ty::Alias(ty::Projection, projection_ty), _)
|
||||
if D::normalization() == NormalizationStrategy::Lazy =>
|
||||
{
|
||||
Ok(self.relate_projection_ty(projection_ty, b))
|
||||
}
|
||||
|
||||
(_, &ty::Alias(ty::Projection, projection_ty))
|
||||
if D::normalization() == NormalizationStrategy::Lazy =>
|
||||
{
|
||||
Ok(self.relate_projection_ty(projection_ty, a))
|
||||
}
|
||||
|
||||
_ => {
|
||||
debug!(?a, ?b, ?self.ambient_variance);
|
||||
|
||||
@ -813,17 +755,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
|
||||
impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
||||
self.delegate.register_obligations(vec![Obligation::new(
|
||||
self.tcx(),
|
||||
ObligationCause::dummy(),
|
||||
self.param_env(),
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEquate(a, b)),
|
||||
)]);
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
self.delegate.register_obligations(
|
||||
obligations
|
||||
.into_iter()
|
||||
.map(|to_pred| {
|
||||
Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.delegate.register_obligations(obligations);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ pub fn explicit_outlives_bounds<'tcx>(
|
||||
.filter_map(move |kind| match kind {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
|
@ -21,16 +21,28 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
recursion_depth: usize,
|
||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let def_id = projection_ty.def_id;
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||
span: self.tcx.def_span(def_id),
|
||||
});
|
||||
let projection =
|
||||
ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
|
||||
let obligation =
|
||||
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
|
||||
obligations.push(obligation);
|
||||
ty_var
|
||||
if self.tcx.trait_solver_next() {
|
||||
// FIXME(-Ztrait-solver=next): Instead of branching here,
|
||||
// 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`
|
||||
// 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);
|
||||
} else {
|
||||
let def_id = projection_ty.def_id;
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::NormalizeProjectionType,
|
||||
span: self.tcx.def_span(def_id),
|
||||
});
|
||||
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
|
||||
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
|
||||
)));
|
||||
let obligation =
|
||||
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
|
||||
obligations.push(obligation);
|
||||
ty_var
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use super::combine::{CombineFields, RelationDir};
|
||||
use super::SubregionOrigin;
|
||||
use super::{ObligationEmittingRelation, SubregionOrigin};
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::Obligation;
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::TyVar;
|
||||
@ -228,8 +227,15 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
self.fields.register_predicates(obligations);
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
}
|
||||
|
@ -294,6 +294,9 @@ impl<'tcx> Elaborator<'tcx> {
|
||||
// Nothing to elaborate
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
// No
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1594,12 +1594,14 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
||||
// Ignore projections, as they can only be global
|
||||
// if the trait bound is global
|
||||
Clause(Clause::Projection(..)) |
|
||||
AliasEq(..) |
|
||||
// Ignore bounds that a user can't type
|
||||
WellFormed(..) |
|
||||
ObjectSafe(..) |
|
||||
ClosureKind(..) |
|
||||
Subtype(..) |
|
||||
Coerce(..) |
|
||||
// FIXME(generic_const_exprs): `ConstEvaluatable` can be written
|
||||
ConstEvaluatable(..) |
|
||||
ConstEquate(..) |
|
||||
Ambiguous |
|
||||
|
@ -2254,6 +2254,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn trait_solver_next(self) -> bool {
|
||||
self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtAt<'tcx> {
|
||||
|
@ -264,10 +264,7 @@ impl FlagComputation {
|
||||
term,
|
||||
})) => {
|
||||
self.add_projection_ty(projection_ty);
|
||||
match term.unpack() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(c) => self.add_const(c),
|
||||
}
|
||||
self.add_term(term);
|
||||
}
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
self.add_substs(slice::from_ref(&arg));
|
||||
@ -287,6 +284,10 @@ impl FlagComputation {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(t1, t2) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,4 +381,11 @@ impl FlagComputation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_term(&mut self, term: ty::Term<'_>) {
|
||||
match term.unpack() {
|
||||
ty::TermKind::Ty(ty) => self.add_ty(ty),
|
||||
ty::TermKind::Const(ct) => self.add_const(ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -545,6 +545,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(_))
|
||||
| PredicateKind::Clause(Clause::TypeOutlives(_))
|
||||
| PredicateKind::Clause(Clause::Projection(_))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::ClosureKind(_, _, _)
|
||||
| PredicateKind::Subtype(_)
|
||||
@ -632,6 +633,12 @@ pub enum PredicateKind<'tcx> {
|
||||
/// A marker predicate that is always ambiguous.
|
||||
/// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
|
||||
Ambiguous,
|
||||
|
||||
/// Separate from `Clause::Projection` which is used for normalization in new solver.
|
||||
/// This predicate requires two terms to be equal to eachother.
|
||||
///
|
||||
/// Only used for new solver
|
||||
AliasEq(Term<'tcx>, Term<'tcx>),
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
@ -963,6 +970,33 @@ impl<'tcx> Term<'tcx> {
|
||||
TermKind::Const(c) => c.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// This function returns `None` for `AliasKind::Opaque`.
|
||||
///
|
||||
/// 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>> {
|
||||
match self.unpack() {
|
||||
TermKind::Ty(ty) => match ty.kind() {
|
||||
ty::Alias(kind, alias_ty) => match kind {
|
||||
AliasKind::Projection => Some(*alias_ty),
|
||||
AliasKind::Opaque => None,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
TermKind::Const(ct) => match ct.kind() {
|
||||
ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def.did, uv.substs)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_infer(&self) -> bool {
|
||||
match self.unpack() {
|
||||
TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(),
|
||||
TermKind::Const(ct) => ct.is_ct_infer(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TAG_MASK: usize = 0b11;
|
||||
@ -1152,6 +1186,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
match predicate.skip_binder() {
|
||||
PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
@ -1171,6 +1206,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
match predicate.skip_binder() {
|
||||
PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
@ -1191,6 +1227,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)),
|
||||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
|
@ -2842,6 +2842,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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +177,7 @@ 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:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::AliasEq(_, _) => {
|
||||
FulfillmentErrorCode::CodeProjectionError(
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::Subtype(pred) => {
|
||||
let (a, b) = infcx.instantiate_binder_with_placeholders(
|
||||
goal.predicate.kind().rebind((pred.a, pred.b)),
|
||||
|
@ -42,6 +42,8 @@ mod trait_goals;
|
||||
|
||||
pub use fulfill::FulfillmentCtxt;
|
||||
|
||||
use self::infcx_ext::InferCtxtExt;
|
||||
|
||||
/// A goal is a statement, i.e. `predicate`, we want to prove
|
||||
/// given some assumptions, i.e. `param_env`.
|
||||
///
|
||||
@ -81,6 +83,21 @@ pub struct Response<'tcx> {
|
||||
pub certainty: Certainty,
|
||||
}
|
||||
|
||||
trait CanonicalResponseExt {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool {
|
||||
// so that we get a compile error when regions are supported
|
||||
// so this code can be checked for being correct
|
||||
let _: () = self.value.external_constraints.regions;
|
||||
|
||||
self.value.var_values.is_identity()
|
||||
&& self.value.external_constraints.opaque_types.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum Certainty {
|
||||
Yes,
|
||||
@ -302,6 +319,9 @@ 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) })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
|
||||
@ -398,6 +418,63 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
None => self.make_canonical_response(Certainty::AMBIGUOUS),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn compute_alias_eq_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
|
||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||
let r = ecx.infcx.probe(|_| {
|
||||
let (_, certainty) = ecx.evaluate_goal(goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: alias,
|
||||
term: other,
|
||||
}),
|
||||
))?;
|
||||
ecx.make_canonical_response(certainty)
|
||||
});
|
||||
debug!("evaluate_normalizes_to(..) -> {:?}", r);
|
||||
r
|
||||
};
|
||||
|
||||
if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
|
||||
bug!(
|
||||
"`AliasEq` 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),
|
||||
(Some(alias_lhs), Some(alias_rhs)) => {
|
||||
debug!("compute_alias_eq_goal: both sides are aliases");
|
||||
|
||||
let mut candidates = Vec::with_capacity(3);
|
||||
|
||||
// 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.infcx.probe(|_| {
|
||||
debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
|
||||
let nested_goals = self.infcx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
self.evaluate_all_and_make_canonical_response(nested_goals)
|
||||
}));
|
||||
|
||||
debug!(?candidates);
|
||||
|
||||
self.try_merge_responses(candidates.into_iter())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
@ -449,6 +526,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
) -> QueryResult<'tcx> {
|
||||
self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
|
||||
}
|
||||
|
||||
fn try_merge_responses(
|
||||
&mut self,
|
||||
responses: impl Iterator<Item = QueryResult<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let candidates = responses.into_iter().flatten().collect::<Box<[_]>>();
|
||||
|
||||
if candidates.is_empty() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with
|
||||
// a subset of the constraints that all the other responses have.
|
||||
let one = candidates[0];
|
||||
if candidates[1..].iter().all(|resp| resp == &one) {
|
||||
return Ok(one);
|
||||
}
|
||||
|
||||
if let Some(response) = candidates.iter().find(|response| {
|
||||
response.value.certainty == Certainty::Yes
|
||||
&& response.has_no_inference_or_external_constraints()
|
||||
}) {
|
||||
return Ok(response.clone());
|
||||
}
|
||||
|
||||
let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
|
||||
certainty.unify_and(response.value.certainty)
|
||||
});
|
||||
// FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the
|
||||
// responses and use that for the constraints of this ambiguous response.
|
||||
let response = self.make_canonical_response(certainty);
|
||||
if let Ok(response) = &response {
|
||||
assert!(response.has_no_inference_or_external_constraints());
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(infcx), ret)]
|
||||
|
@ -823,14 +823,17 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
|
||||
// There's not really much we can do with these predicates -
|
||||
// we start out with a `ParamEnv` with no inference variables,
|
||||
// and these don't correspond to adding any new bounds to
|
||||
// the `ParamEnv`.
|
||||
ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::infer::InferCtxt;
|
||||
|
||||
use rustc_infer::infer::ObligationEmittingRelation;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -88,3 +90,16 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
||||
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
|
||||
fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
|
||||
// FIXME(deferred_projection_equality)
|
||||
}
|
||||
|
||||
fn register_predicates(
|
||||
&mut self,
|
||||
_obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
|
||||
) {
|
||||
// FIXME(deferred_projection_equality)
|
||||
}
|
||||
}
|
||||
|
@ -1278,6 +1278,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
span,
|
||||
"TypeWellFormedFromEnv predicate should only exist in the environment"
|
||||
),
|
||||
|
||||
ty::PredicateKind::AliasEq(..) => span_bug!(
|
||||
span,
|
||||
"AliasEq predicate should never be the predicate cause of a SelectionError"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,6 +328,9 @@ 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")
|
||||
}
|
||||
},
|
||||
Some(pred) => match pred {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
|
||||
@ -594,6 +597,9 @@ 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")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -327,6 +327,8 @@ fn predicate_references_self<'tcx>(
|
||||
// possible alternatives.
|
||||
if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
||||
}
|
||||
ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
|
||||
|
||||
ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||
@ -334,6 +336,7 @@ fn predicate_references_self<'tcx>(
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
// FIXME(generic_const_exprs): this can mention `Self`
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
@ -368,6 +371,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::Ambiguous
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
|
||||
}
|
||||
|
@ -991,6 +991,9 @@ 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::Ambiguous => Ok(EvaluatedToAmbig),
|
||||
}
|
||||
})
|
||||
|
@ -187,6 +187,9 @@ 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`")
|
||||
}
|
||||
}
|
||||
|
||||
wf.normalize(infcx)
|
||||
@ -928,6 +931,7 @@ pub(crate) fn required_region_bounds<'tcx>(
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
|
||||
ref t,
|
||||
|
@ -116,6 +116,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
|
||||
)),
|
||||
},
|
||||
ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
@ -210,6 +211,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
|
||||
// We can defer this, but ultimately we'll want to express
|
||||
// some of these in terms of chalk operations.
|
||||
ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
@ -645,6 +647,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
|
||||
ty::PredicateKind::WellFormed(_ty) => None,
|
||||
|
||||
ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
@ -778,6 +781,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
|
||||
ty::PredicateKind::WellFormed(_ty) => None,
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
@ -85,7 +85,8 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
// learn anything new from those.
|
||||
if obligation.predicate.has_non_region_infer() {
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..)) => {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::AliasEq(..) => {
|
||||
ocx.register_obligation(obligation.clone());
|
||||
}
|
||||
_ => {}
|
||||
@ -106,6 +107,7 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
|
||||
// We need to search through *all* WellFormed predicates
|
||||
|
@ -60,6 +60,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false,
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
|
@ -311,10 +311,12 @@ pub(crate) fn clean_predicate<'tcx>(
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
|
||||
Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
|
||||
}
|
||||
// FIXME(generic_const_exprs): should this do something?
|
||||
ty::PredicateKind::ConstEvaluatable(..) => None,
|
||||
ty::PredicateKind::WellFormed(..) => None,
|
||||
|
||||
ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
|
@ -36,6 +36,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::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:#?}"),
|
||||
|
@ -0,0 +1,29 @@
|
||||
// check-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// check that a goal such as `alias-eq(<T as TraitB>::Assoc<bool>, <T as TraitB>::Assoc<?0>)`
|
||||
// succeeds with a constraint that `?0 = bool`
|
||||
|
||||
// FIXME(deferred_projection_equality): add a test that this is true during coherence
|
||||
|
||||
trait TraitA {}
|
||||
|
||||
trait TraitB {
|
||||
type Assoc<T: ?Sized>;
|
||||
}
|
||||
|
||||
impl<T: TraitB> TraitA for (T, T::Assoc<bool>) {}
|
||||
|
||||
impl TraitB for i32 {
|
||||
type Assoc<T: ?Sized> = u32;
|
||||
}
|
||||
|
||||
fn needs_a<T: TraitA>() {}
|
||||
|
||||
fn bar<T: TraitB>() {
|
||||
needs_a::<(T, <T as TraitB>::Assoc<_>)>();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
bar::<i32>();
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// check that when computing `alias-eq(<() as Foo<u16, T>>::Assoc, <() as Foo<?0, T>>::Assoc)`
|
||||
// we do not infer `?0 = u8` via the `for<STOP> (): Foo<u8, STOP>` impl or `?0 = u16` by
|
||||
// relating substs as either could be a valid solution.
|
||||
|
||||
trait Foo<T, STOP> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<STOP> Foo<u8, STOP> for ()
|
||||
where
|
||||
(): Foo<u16, STOP>,
|
||||
{
|
||||
type Assoc = <() as Foo<u16, STOP>>::Assoc;
|
||||
}
|
||||
|
||||
impl Foo<u16, i8> for () {
|
||||
type Assoc = u8;
|
||||
}
|
||||
|
||||
impl Foo<u16, i16> for () {
|
||||
type Assoc = u16;
|
||||
}
|
||||
|
||||
fn output<T, U>() -> <() as Foo<T, U>>::Assoc
|
||||
where
|
||||
(): Foo<T, U>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn incomplete<T>()
|
||||
where
|
||||
(): Foo<u16, T>,
|
||||
{
|
||||
// `<() as Foo<u16, STOP>>::Assoc == <() as Foo<_, STOP>>::Assoc`
|
||||
let _: <() as Foo<u16, T>>::Assoc = output::<_, T>();
|
||||
//~^ error: type annotations needed
|
||||
|
||||
// let _: <() as Foo<u16, T>>::Assoc = output::<u8, T>(); // OK
|
||||
// let _: <() as Foo<u16, T>>::Assoc = output::<u16, T>(); // OK
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,9 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/alias_eq_dont_use_normalizes_to_if_substs_eq.rs:38:41
|
||||
|
|
||||
LL | let _: <() as Foo<u16, T>>::Assoc = output::<_, T>();
|
||||
| ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `output`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
22
tests/ui/traits/new-solver/alias_eq_simple.rs
Normal file
22
tests/ui/traits/new-solver/alias_eq_simple.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// check-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// test that the new solver can handle `alias-eq(<i32 as TraitB>::Assoc, u32)`
|
||||
|
||||
trait TraitA {}
|
||||
|
||||
trait TraitB {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T: TraitB> TraitA for (T, T::Assoc) {}
|
||||
|
||||
impl TraitB for i32 {
|
||||
type Assoc = u32;
|
||||
}
|
||||
|
||||
fn needs_a<T: TraitA>() {}
|
||||
|
||||
fn main() {
|
||||
needs_a::<(i32, u32)>();
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
|
||||
// check that a `alias-eq(<?0 as TraitB>::Assoc, <T as TraitB>::Assoc)` goal fails.
|
||||
|
||||
// FIXME(deferred_projection_equality): add a test that this is true during coherence
|
||||
|
||||
trait TraitB {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
fn needs_a<T: TraitB>() -> T::Assoc {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn bar<T: TraitB>() {
|
||||
let _: <_ as TraitB>::Assoc = needs_a::<T>();
|
||||
//~^ error: type annotations needed
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,9 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/alias_eq_substs_eq_not_intercrate.rs:16:12
|
||||
|
|
||||
LL | let _: <_ as TraitB>::Assoc = needs_a::<T>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type for associated type `<_ as TraitB>::Assoc`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
@ -0,0 +1,40 @@
|
||||
// [no_self_infer] check-pass
|
||||
// compile-flags: -Ztrait-solver=next
|
||||
// revisions: self_infer no_self_infer
|
||||
|
||||
// checks that the new solver is smart enough to infer `?0 = U` when solving:
|
||||
// `normalizes-to(<Vec<?0> as Trait>::Assoc, u8)`
|
||||
// with `normalizes-to(<Vec<U> as Trait>::Assoc, u8)` in the paramenv even when
|
||||
// there is a separate `Vec<T>: Trait` bound in the paramenv.
|
||||
//
|
||||
// FIXME(-Ztrait-solver=next)
|
||||
// This could also compile for `normalizes-to(<?0 as Trait>::Assoc, u8)` but
|
||||
// we currently immediately consider a goal ambiguous if the self type is an
|
||||
// inference variable.
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
fn foo<T: Trait<Assoc = u8>>(x: T) {}
|
||||
|
||||
#[cfg(self_infer)]
|
||||
fn unconstrained<T>() -> T {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(no_self_infer)]
|
||||
fn unconstrained<T>() -> Vec<T> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn bar<T, U>()
|
||||
where
|
||||
Vec<T>: Trait,
|
||||
Vec<U>: Trait<Assoc = u8>,
|
||||
{
|
||||
foo(unconstrained())
|
||||
//[self_infer]~^ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,14 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:36:5
|
||||
|
|
||||
LL | foo(unconstrained())
|
||||
| ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
||||
|
|
||||
help: consider specifying the generic argument
|
||||
|
|
||||
LL | foo::<T>(unconstrained())
|
||||
| +++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
Loading…
Reference in New Issue
Block a user