Replace RelationDir with Variance

This commit is contained in:
Michael Goulet 2023-05-15 17:00:16 +00:00
parent 41501c7449
commit a2678e15e5
4 changed files with 29 additions and 63 deletions

View file

@ -48,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> {
pub define_opaque_types: DefineOpaqueTypes,
}
#[derive(Copy, Clone, Debug)]
pub enum RelationDir {
SubtypeOf,
SupertypeOf,
EqTo,
}
impl<'tcx> InferCtxt<'tcx> {
pub fn super_combine_tys<R>(
&self,
@ -378,12 +371,10 @@ pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'tcx> {
pub fn instantiate(
&mut self,
a_ty: Ty<'tcx>,
dir: RelationDir,
ambient_variance: ty::Variance,
b_vid: ty::TyVid,
a_is_expected: bool,
) -> RelateResult<'tcx, ()> {
use self::RelationDir::*;
// Get the actual variable that b_vid has been inferred to
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
@ -398,7 +389,18 @@ pub fn instantiate(
// `'?2` and `?3` are fresh region/type inference
// variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
let Generalization { value: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
let Generalization { value: b_ty, needs_wf } = generalize::generalize(
self.infcx,
&mut CombineDelegate {
infcx: self.infcx,
param_env: self.param_env,
span: self.trace.span(),
},
a_ty,
b_vid,
ambient_variance,
)?;
debug!(?b_ty);
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
@ -417,62 +419,23 @@ pub fn instantiate(
// relations wind up attributed to the same spans. We need
// to associate causes/spans with each of the relations in
// the stack to get this right.
match dir {
EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
SupertypeOf => self.sub(a_is_expected).relate_with_variance(
match ambient_variance {
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
ty::Contravariant,
ty::VarianceDiagInfo::default(),
a_ty,
b_ty,
),
ty::Variance::Bivariant => {
unreachable!("no code should be generalizing bivariantly (currently)")
}
}?;
Ok(())
}
/// Attempts to generalize `ty` for the type variable `for_vid`.
/// This checks for cycle -- that is, whether the type `ty`
/// references `for_vid`. The `dir` is the "direction" for which we
/// a performing the generalization (i.e., are we producing a type
/// that can be used as a supertype etc).
///
/// Preconditions:
///
/// - `for_vid` is a "root vid"
#[instrument(skip(self), level = "trace", ret)]
fn generalize(
&mut self,
ty: Ty<'tcx>,
for_vid: ty::TyVid,
dir: RelationDir,
) -> RelateResult<'tcx, Generalization<Ty<'tcx>>> {
// Determine the ambient variance within which `ty` appears.
// The surrounding equation is:
//
// ty [op] ty2
//
// where `op` is either `==`, `<:`, or `:>`. This maps quite
// naturally.
let ambient_variance = match dir {
RelationDir::EqTo => ty::Invariant,
RelationDir::SubtypeOf => ty::Covariant,
RelationDir::SupertypeOf => ty::Contravariant,
};
generalize::generalize(
self.infcx,
&mut CombineDelegate {
infcx: self.infcx,
param_env: self.param_env,
span: self.trace.span(),
},
ty,
for_vid,
ambient_variance,
)
}
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.obligations.extend(obligations.into_iter());
}

View file

@ -1,7 +1,7 @@
use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations;
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::Subtype;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@ -88,11 +88,11 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
}
(&ty::Infer(TyVar(a_id)), _) => {
self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?;
}
(_, &ty::Infer(TyVar(b_id))) => {
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?;
}
(

View file

@ -10,6 +10,9 @@
use crate::infer::type_variable::TypeVariableValue;
use crate::infer::{InferCtxt, RegionVariableOrigin};
/// Attempts to generalize `term` for the type variable `for_vid`.
/// This checks for cycles -- that is, whether the type `term`
/// references `for_vid`.
pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>(
infcx: &InferCtxt<'tcx>,
delegate: &mut D,

View file

@ -1,4 +1,4 @@
use super::combine::{CombineFields, RelationDir};
use super::combine::CombineFields;
use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
@ -108,11 +108,11 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
Ok(a)
}
(&ty::Infer(TyVar(a_id)), _) => {
self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?;
self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?;
Ok(a)
}
(_, &ty::Infer(TyVar(b_id))) => {
self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?;
self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?;
Ok(a)
}