1
Fork 0

Implement fallback for effect param

This commit is contained in:
Deadbeef 2023-09-10 05:11:37 +00:00
parent b14b0745ad
commit 84a490712a
20 changed files with 390 additions and 72 deletions

View file

@ -173,6 +173,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(..) => true,
CanonicalVarKind::PlaceholderConst(_, _) => false,
CanonicalVarKind::Effect => true,
}
}
@ -182,7 +183,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
CanonicalVarKind::Ty(_)
| CanonicalVarKind::PlaceholderTy(_)
| CanonicalVarKind::Const(_, _)
| CanonicalVarKind::PlaceholderConst(_, _) => false,
| CanonicalVarKind::PlaceholderConst(_, _)
| CanonicalVarKind::Effect => false,
}
}
@ -190,7 +192,8 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
match self.kind {
CanonicalVarKind::Ty(_)
| CanonicalVarKind::Region(_)
| CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"),
| CanonicalVarKind::Const(_, _)
| CanonicalVarKind::Effect => bug!("expected placeholder: {self:?}"),
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(),
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(),
@ -222,6 +225,9 @@ pub enum CanonicalVarKind<'tcx> {
/// Some kind of const inference variable.
Const(ty::UniverseIndex, Ty<'tcx>),
/// Effect variable `'?E`.
Effect,
/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
}
@ -229,11 +235,11 @@ pub enum CanonicalVarKind<'tcx> {
impl<'tcx> CanonicalVarKind<'tcx> {
pub fn universe(self) -> ty::UniverseIndex {
match self {
CanonicalVarKind::Ty(kind) => match kind {
CanonicalTyVarKind::General(ui) => ui,
CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
},
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
ty::UniverseIndex::ROOT
}
CanonicalVarKind::Effect => ty::UniverseIndex::ROOT,
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
@ -248,15 +254,14 @@ impl<'tcx> CanonicalVarKind<'tcx> {
/// the updated universe is not the root.
pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> {
match self {
CanonicalVarKind::Ty(kind) => match kind {
CanonicalTyVarKind::General(_) => {
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
}
CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
assert_eq!(ui, ty::UniverseIndex::ROOT);
CanonicalVarKind::Ty(kind)
}
},
CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => {
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
}
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
| CanonicalVarKind::Effect => {
assert_eq!(ui, ty::UniverseIndex::ROOT);
self
}
CanonicalVarKind::PlaceholderTy(placeholder) => {
CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder })
}
@ -443,6 +448,14 @@ impl<'tcx> CanonicalVarValues<'tcx> {
};
ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into()
}
// todo eh?
CanonicalVarKind::Effect => ty::Const::new_bound(
tcx,
ty::INNERMOST,
ty::BoundVar::from_usize(i),
tcx.types.bool,
)
.into(),
CanonicalVarKind::Const(_, ty)
| CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
tcx,

View file

@ -188,3 +188,53 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
})
}
}
/// values for the effect inference variable
#[derive(Clone, Copy, Debug)]
pub enum EffectVarValue<'tcx> {
/// The host effect is on, enabling access to syscalls, filesystem access, etc.
Host,
/// The host effect is off. Execution is restricted to const operations only.
NoHost,
Const(ty::Const<'tcx>),
}
impl<'tcx> EffectVarValue<'tcx> {
pub fn as_const(self, tcx: TyCtxt<'tcx>) -> ty::Const<'tcx> {
match self {
EffectVarValue::Host => tcx.consts.true_,
EffectVarValue::NoHost => tcx.consts.false_,
EffectVarValue::Const(c) => c,
}
}
}
impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
type Error = (EffectVarValue<'tcx>, EffectVarValue<'tcx>);
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
match (value1, value2) {
(EffectVarValue::Host, EffectVarValue::Host) => Ok(EffectVarValue::Host),
(EffectVarValue::NoHost, EffectVarValue::NoHost) => Ok(EffectVarValue::NoHost),
(EffectVarValue::NoHost | EffectVarValue::Host, _)
| (_, EffectVarValue::NoHost | EffectVarValue::Host) => Err((*value1, *value2)),
(EffectVarValue::Const(_), EffectVarValue::Const(_)) => {
bug!("equating two const variables, both of which have known values")
}
}
}
}
impl<'tcx> UnifyKey for ty::EffectVid<'tcx> {
type Value = Option<EffectVarValue<'tcx>>;
#[inline]
fn index(&self) -> u32 {
self.index
}
#[inline]
fn from_index(i: u32) -> Self {
ty::EffectVid { index: i, phantom: PhantomData }
}
fn tag() -> &'static str {
"EffectVid"
}
}

View file

@ -55,6 +55,11 @@ static_assert_size!(super::ConstKind<'_>, 32);
pub enum InferConst<'tcx> {
/// Infer the value of the const.
Var(ty::ConstVid<'tcx>),
/// Infer the value of the effect.
///
/// For why this is separate from the `Var` variant above, see the
/// documentation on `EffectVid`.
EffectVar(ty::EffectVid<'tcx>),
/// A fresh const variable. See `infer::freshen` for more details.
Fresh(u32),
}
@ -62,7 +67,9 @@ pub enum InferConst<'tcx> {
impl<CTX> HashStable<CTX> for InferConst<'_> {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
match self {
InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
InferConst::Var(_) | InferConst::EffectVar(_) => {
panic!("const variables should not be hashed: {self:?}")
}
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
}
}

View file

@ -324,7 +324,9 @@ impl FlagComputation {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
InferConst::Var(_) | InferConst::EffectVar(_) => {
self.add_flags(TypeFlags::HAS_CT_INFER)
}
}
}
ty::ConstKind::Bound(debruijn, _) => {

View file

@ -98,9 +98,9 @@ pub use self::sty::BoundRegionKind::*;
pub use self::sty::{
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs, InlineConstArgsParts,
ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
FnSig, FreeRegion, GenSig, GeneratorArgs, GeneratorArgsParts, InlineConstArgs,
InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
};

View file

@ -138,6 +138,12 @@ impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
}
}
impl fmt::Debug for ty::EffectVid<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "?{}e", self.index)
}
}
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@ -253,6 +259,7 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InferConst::Var(var) => write!(f, "{var:?}"),
InferConst::EffectVar(var) => write!(f, "{var:?}"),
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
}
}
@ -267,6 +274,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data {
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()),
Fresh(_) => {
unreachable!()
}

View file

@ -1577,6 +1577,20 @@ pub struct ConstVid<'tcx> {
pub phantom: PhantomData<&'tcx ()>,
}
/// An **effect** **v**ariable **ID**.
///
/// Handling effect infer variables happens separately from const infer variables
/// because we do not want to reuse any of the const infer machinery. If we try to
/// relate an effect variable with a normal one, we would ICE, which can catch bugs
/// where we are not correctly using the effect var for an effect param. Fallback
/// is also implemented on top of having separate effect and normal const variables.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable)]
pub struct EffectVid<'tcx> {
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
}
rustc_index::newtype_index! {
/// A **region** (lifetime) **v**ariable **ID**.
#[derive(HashStable)]