Introduce SolverRelating
This commit is contained in:
parent
ce7a61b9d0
commit
efb1c23ff6
8 changed files with 387 additions and 4 deletions
|
@ -136,6 +136,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
self.enter_forall(value, f)
|
self.enter_forall(value, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) {
|
||||||
|
self.inner.borrow_mut().type_variables().equate(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
|
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
|
||||||
self.inner.borrow_mut().int_unification_table().union(a, b);
|
self.inner.borrow_mut().int_unification_table().union(a, b);
|
||||||
}
|
}
|
||||||
|
@ -152,6 +156,23 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
self.inner.borrow_mut().effect_unification_table().union(a, b);
|
self.inner.borrow_mut().effect_unification_table().union(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
target_is_expected: bool,
|
||||||
|
target_vid: rustc_type_ir::TyVid,
|
||||||
|
instantiation_variance: rustc_type_ir::Variance,
|
||||||
|
source_ty: Ty<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, ()> {
|
||||||
|
self.instantiate_ty_var(
|
||||||
|
relation,
|
||||||
|
target_is_expected,
|
||||||
|
target_vid,
|
||||||
|
instantiation_variance,
|
||||||
|
source_ty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn instantiate_int_var_raw(
|
fn instantiate_int_var_raw(
|
||||||
&self,
|
&self,
|
||||||
vid: rustc_type_ir::IntVid,
|
vid: rustc_type_ir::IntVid,
|
||||||
|
@ -228,7 +249,19 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||||
self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), sub, sup)
|
self.inner.borrow_mut().unwrap_region_constraints().make_subregion(
|
||||||
|
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
|
||||||
|
sub,
|
||||||
|
sup,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
|
||||||
|
self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(
|
||||||
|
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||||
|
|
|
@ -698,6 +698,12 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {
|
||||||
|
fn dummy() -> Self {
|
||||||
|
DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||||
|
|
||||||
pub struct CtxtInterners<'tcx> {
|
pub struct CtxtInterners<'tcx> {
|
||||||
|
|
|
@ -67,11 +67,20 @@ pub trait InferCtxtLike: Sized {
|
||||||
f: impl FnOnce(T) -> U,
|
f: impl FnOnce(T) -> U,
|
||||||
) -> U;
|
) -> U;
|
||||||
|
|
||||||
|
fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
|
||||||
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
|
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
|
||||||
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
|
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
|
||||||
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
|
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
|
||||||
fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
|
fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
|
||||||
|
|
||||||
|
fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
|
||||||
|
&self,
|
||||||
|
relation: &mut R,
|
||||||
|
target_is_expected: bool,
|
||||||
|
target_vid: ty::TyVid,
|
||||||
|
instantiation_variance: ty::Variance,
|
||||||
|
source_ty: <Self::Interner as Interner>::Ty,
|
||||||
|
) -> RelateResult<Self::Interner, ()>;
|
||||||
fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
|
fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
|
||||||
fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
|
fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
|
||||||
fn instantiate_effect_var_raw(
|
fn instantiate_effect_var_raw(
|
||||||
|
@ -125,6 +134,12 @@ pub trait InferCtxtLike: Sized {
|
||||||
sup: <Self::Interner as Interner>::Region,
|
sup: <Self::Interner as Interner>::Region,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fn equate_regions(
|
||||||
|
&self,
|
||||||
|
a: <Self::Interner as Interner>::Region,
|
||||||
|
b: <Self::Interner as Interner>::Region,
|
||||||
|
);
|
||||||
|
|
||||||
fn register_ty_outlives(
|
fn register_ty_outlives(
|
||||||
&self,
|
&self,
|
||||||
ty: <Self::Interner as Interner>::Ty,
|
ty: <Self::Interner as Interner>::Ty,
|
||||||
|
|
|
@ -565,6 +565,10 @@ pub trait BoundExistentialPredicates<I: Interner>:
|
||||||
) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>;
|
) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Span<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||||
|
fn dummy() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait SliceLike: Sized + Copy {
|
pub trait SliceLike: Sized + Copy {
|
||||||
type Item: Copy;
|
type Item: Copy;
|
||||||
type IntoIter: Iterator<Item = Self::Item>;
|
type IntoIter: Iterator<Item = Self::Item>;
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub trait Interner:
|
||||||
{
|
{
|
||||||
type DefId: DefId<Self>;
|
type DefId: DefId<Self>;
|
||||||
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
|
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
|
||||||
type Span: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
|
type Span: Span<Self>;
|
||||||
|
|
||||||
type GenericArgs: GenericArgs<Self>;
|
type GenericArgs: GenericArgs<Self>;
|
||||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>;
|
type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>;
|
||||||
|
|
|
@ -206,8 +206,8 @@ pub fn debug_bound_var<T: std::fmt::Write>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, Hash, HashStable_NoContext))]
|
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, HashStable_NoContext))]
|
||||||
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
|
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
|
||||||
pub enum Variance {
|
pub enum Variance {
|
||||||
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
|
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::inherent::*;
|
||||||
use crate::{self as ty, Interner};
|
use crate::{self as ty, Interner};
|
||||||
|
|
||||||
pub mod combine;
|
pub mod combine;
|
||||||
|
pub mod solver_relating;
|
||||||
|
|
||||||
pub type RelateResult<I, T> = Result<T, TypeError<I>>;
|
pub type RelateResult<I, T> = Result<T, TypeError<I>>;
|
||||||
|
|
||||||
|
|
324
compiler/rustc_type_ir/src/relate/solver_relating.rs
Normal file
324
compiler/rustc_type_ir/src/relate/solver_relating.rs
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
pub use rustc_type_ir::relate::*;
|
||||||
|
use rustc_type_ir::solve::Goal;
|
||||||
|
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
use self::combine::{InferCtxtCombineExt, PredicateEmittingRelation};
|
||||||
|
use crate::data_structures::DelayedSet;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
/// Enforce that `a` is equal to or a subtype of `b`.
|
||||||
|
pub struct SolverRelating<'infcx, Infcx, I: Interner> {
|
||||||
|
infcx: &'infcx Infcx,
|
||||||
|
// Immutable fields.
|
||||||
|
structurally_relate_aliases: StructurallyRelateAliases,
|
||||||
|
param_env: I::ParamEnv,
|
||||||
|
// Mutable fields.
|
||||||
|
ambient_variance: ty::Variance,
|
||||||
|
goals: Vec<Goal<I, I::Predicate>>,
|
||||||
|
/// The cache only tracks the `ambient_variance` as it's the
|
||||||
|
/// only field which is mutable and which meaningfully changes
|
||||||
|
/// the result when relating types.
|
||||||
|
///
|
||||||
|
/// The cache does not track whether the state of the
|
||||||
|
/// `Infcx` has been changed or whether we've added any
|
||||||
|
/// goals to `self.goals`. Whether a goal is added once or multiple
|
||||||
|
/// times is not really meaningful.
|
||||||
|
///
|
||||||
|
/// Changes in the inference state may delay some type inference to
|
||||||
|
/// the next fulfillment loop. Given that this loop is already
|
||||||
|
/// necessary, this is also not a meaningful change. Consider
|
||||||
|
/// the following three relations:
|
||||||
|
/// ```text
|
||||||
|
/// Vec<?0> sub Vec<?1>
|
||||||
|
/// ?0 eq u32
|
||||||
|
/// Vec<?0> sub Vec<?1>
|
||||||
|
/// ```
|
||||||
|
/// Without a cache, the second `Vec<?0> sub Vec<?1>` would eagerly
|
||||||
|
/// constrain `?1` to `u32`. When using the cache entry from the
|
||||||
|
/// first time we've related these types, this only happens when
|
||||||
|
/// later proving the `Subtype(?0, ?1)` goal from the first relation.
|
||||||
|
cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I>
|
||||||
|
where
|
||||||
|
Infcx: InferCtxtLike<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Infcx, I> TypeRelation<I> for SolverRelating<'_, Infcx, I>
|
||||||
|
where
|
||||||
|
Infcx: InferCtxtLike<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
fn cx(&self) -> I {
|
||||||
|
self.infcx.cx()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relate_item_args(
|
||||||
|
&mut self,
|
||||||
|
item_def_id: I::DefId,
|
||||||
|
a_arg: I::GenericArgs,
|
||||||
|
b_arg: I::GenericArgs,
|
||||||
|
) -> RelateResult<I, I::GenericArgs> {
|
||||||
|
if self.ambient_variance == ty::Invariant {
|
||||||
|
// Avoid fetching the variance if we are in an invariant
|
||||||
|
// context; no need, and it can induce dependency cycles
|
||||||
|
// (e.g., #41849).
|
||||||
|
relate_args_invariantly(self, a_arg, b_arg)
|
||||||
|
} else {
|
||||||
|
let tcx = self.cx();
|
||||||
|
let opt_variances = tcx.variances_of(item_def_id);
|
||||||
|
relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relate_with_variance<T: Relate<I>>(
|
||||||
|
&mut self,
|
||||||
|
variance: ty::Variance,
|
||||||
|
_info: VarianceDiagInfo<I>,
|
||||||
|
a: T,
|
||||||
|
b: T,
|
||||||
|
) -> RelateResult<I, T> {
|
||||||
|
let old_ambient_variance = self.ambient_variance;
|
||||||
|
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||||
|
debug!(?self.ambient_variance, "new ambient variance");
|
||||||
|
|
||||||
|
let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
|
||||||
|
|
||||||
|
self.ambient_variance = old_ambient_variance;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "trace")]
|
||||||
|
fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
|
||||||
|
if a == b {
|
||||||
|
return Ok(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
let infcx = self.infcx;
|
||||||
|
let a = infcx.shallow_resolve(a);
|
||||||
|
let b = infcx.shallow_resolve(b);
|
||||||
|
|
||||||
|
if self.cache.contains(&(self.ambient_variance, a, b)) {
|
||||||
|
return Ok(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
match (a.kind(), b.kind()) {
|
||||||
|
(ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
|
||||||
|
match self.ambient_variance {
|
||||||
|
ty::Covariant => {
|
||||||
|
// can't make progress on `A <: B` if both A and B are
|
||||||
|
// type variables, so record an obligation.
|
||||||
|
self.goals.push(Goal::new(
|
||||||
|
self.cx(),
|
||||||
|
self.param_env,
|
||||||
|
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
|
||||||
|
a_is_expected: true,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
})),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
ty::Contravariant => {
|
||||||
|
// can't make progress on `B <: A` if both A and B are
|
||||||
|
// type variables, so record an obligation.
|
||||||
|
self.goals.push(Goal::new(
|
||||||
|
self.cx(),
|
||||||
|
self.param_env,
|
||||||
|
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
|
||||||
|
a_is_expected: false,
|
||||||
|
a: b,
|
||||||
|
b: a,
|
||||||
|
})),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
ty::Invariant => {
|
||||||
|
infcx.equate_ty_vids_raw(a_id, b_id);
|
||||||
|
}
|
||||||
|
ty::Bivariant => {
|
||||||
|
unreachable!("Expected bivariance to be handled in relate_with_variance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty::Infer(ty::TyVar(a_vid)), _) => {
|
||||||
|
infcx.instantiate_ty_var_raw(self, true, a_vid, self.ambient_variance, b)?;
|
||||||
|
}
|
||||||
|
(_, ty::Infer(ty::TyVar(b_vid))) => {
|
||||||
|
infcx.instantiate_ty_var_raw(
|
||||||
|
self,
|
||||||
|
false,
|
||||||
|
b_vid,
|
||||||
|
self.ambient_variance.xform(ty::Contravariant),
|
||||||
|
a,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
self.infcx.super_combine_tys(self, a, b)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(self.cache.insert((self.ambient_variance, a, b)));
|
||||||
|
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "trace")]
|
||||||
|
fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
|
||||||
|
match self.ambient_variance {
|
||||||
|
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
|
||||||
|
ty::Covariant => self.infcx.sub_regions(b, a),
|
||||||
|
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
|
||||||
|
ty::Contravariant => self.infcx.sub_regions(a, b),
|
||||||
|
ty::Invariant => self.infcx.equate_regions(a, b),
|
||||||
|
ty::Bivariant => {
|
||||||
|
unreachable!("Expected bivariance to be handled in relate_with_variance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "trace")]
|
||||||
|
fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> {
|
||||||
|
self.infcx.super_combine_consts(self, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binders<T>(
|
||||||
|
&mut self,
|
||||||
|
a: ty::Binder<I, T>,
|
||||||
|
b: ty::Binder<I, T>,
|
||||||
|
) -> RelateResult<I, ty::Binder<I, T>>
|
||||||
|
where
|
||||||
|
T: Relate<I>,
|
||||||
|
{
|
||||||
|
// If they're equal, then short-circuit.
|
||||||
|
if a == b {
|
||||||
|
return Ok(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they have no bound vars, relate normally.
|
||||||
|
if let Some(a_inner) = a.no_bound_vars() {
|
||||||
|
if let Some(b_inner) = b.no_bound_vars() {
|
||||||
|
self.relate(a_inner, b_inner)?;
|
||||||
|
return Ok(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.ambient_variance {
|
||||||
|
// Checks whether `for<..> sub <: for<..> sup` holds.
|
||||||
|
//
|
||||||
|
// For this to hold, **all** instantiations of the super type
|
||||||
|
// have to be a super type of **at least one** instantiation of
|
||||||
|
// the subtype.
|
||||||
|
//
|
||||||
|
// This is implemented by first entering a new universe.
|
||||||
|
// We then replace all bound variables in `sup` with placeholders,
|
||||||
|
// and all bound variables in `sub` with inference vars.
|
||||||
|
// We can then just relate the two resulting types as normal.
|
||||||
|
//
|
||||||
|
// Note: this is a subtle algorithm. For a full explanation, please see
|
||||||
|
// the [rustc dev guide][rd]
|
||||||
|
//
|
||||||
|
// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
|
||||||
|
ty::Covariant => {
|
||||||
|
self.infcx.enter_forall(b, |b| {
|
||||||
|
let a = self.infcx.instantiate_binder_with_infer(a);
|
||||||
|
self.relate(a, b)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
ty::Contravariant => {
|
||||||
|
self.infcx.enter_forall(a, |a| {
|
||||||
|
let b = self.infcx.instantiate_binder_with_infer(b);
|
||||||
|
self.relate(a, b)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When **equating** binders, we check that there is a 1-to-1
|
||||||
|
// correspondence between the bound vars in both types.
|
||||||
|
//
|
||||||
|
// We do so by separately instantiating one of the binders with
|
||||||
|
// placeholders and the other with inference variables and then
|
||||||
|
// equating the instantiated types.
|
||||||
|
//
|
||||||
|
// We want `for<..> A == for<..> B` -- therefore we want
|
||||||
|
// `exists<..> A == for<..> B` and `exists<..> B == for<..> A`.
|
||||||
|
// Check if `exists<..> A == for<..> B`
|
||||||
|
ty::Invariant => {
|
||||||
|
self.infcx.enter_forall(b, |b| {
|
||||||
|
let a = self.infcx.instantiate_binder_with_infer(a);
|
||||||
|
self.relate(a, b)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Check if `exists<..> B == for<..> A`.
|
||||||
|
self.infcx.enter_forall(a, |a| {
|
||||||
|
let b = self.infcx.instantiate_binder_with_infer(b);
|
||||||
|
self.relate(a, b)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
ty::Bivariant => {
|
||||||
|
unreachable!("Expected bivariance to be handled in relate_with_variance")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Infcx, I> PredicateEmittingRelation<Infcx> for SolverRelating<'_, Infcx, I>
|
||||||
|
where
|
||||||
|
Infcx: InferCtxtLike<Interner = I>,
|
||||||
|
I: Interner,
|
||||||
|
{
|
||||||
|
fn span(&self) -> I::Span {
|
||||||
|
Span::dummy()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param_env(&self) -> I::ParamEnv {
|
||||||
|
self.param_env
|
||||||
|
}
|
||||||
|
|
||||||
|
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
|
||||||
|
self.structurally_relate_aliases
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_predicates(
|
||||||
|
&mut self,
|
||||||
|
obligations: impl IntoIterator<Item: ty::Upcast<I, I::Predicate>>,
|
||||||
|
) {
|
||||||
|
self.goals.extend(
|
||||||
|
obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>) {
|
||||||
|
self.goals.extend(obligations);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) {
|
||||||
|
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||||
|
ty::Covariant => ty::PredicateKind::AliasRelate(
|
||||||
|
a.into(),
|
||||||
|
b.into(),
|
||||||
|
ty::AliasRelationDirection::Subtype,
|
||||||
|
),
|
||||||
|
// a :> b is b <: a
|
||||||
|
ty::Contravariant => ty::PredicateKind::AliasRelate(
|
||||||
|
b.into(),
|
||||||
|
a.into(),
|
||||||
|
ty::AliasRelationDirection::Subtype,
|
||||||
|
),
|
||||||
|
ty::Invariant => ty::PredicateKind::AliasRelate(
|
||||||
|
a.into(),
|
||||||
|
b.into(),
|
||||||
|
ty::AliasRelationDirection::Equate,
|
||||||
|
),
|
||||||
|
ty::Bivariant => {
|
||||||
|
unreachable!("Expected bivariance to be handled in relate_with_variance")
|
||||||
|
}
|
||||||
|
})]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue