blob: c35799ef47f2b6d4dc6be46a962371ab798e53c0 [file] [log] [blame]
use crate::ty::{self, Region, Ty, TyCtxt};
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
use rustc_span::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use std::cmp;
use std::marker::PhantomData;
pub trait ToType {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct UnifiedRegion<'tcx> {
value: Option<ty::Region<'tcx>>,
}
impl<'tcx> UnifiedRegion<'tcx> {
pub fn new(value: Option<Region<'tcx>>) -> Self {
Self { value }
}
/// The caller is responsible for checking universe compatibility before using this value.
pub fn get_value_ignoring_universes(self) -> Option<Region<'tcx>> {
self.value
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey<'tcx> {
pub vid: ty::RegionVid,
pub phantom: PhantomData<UnifiedRegion<'tcx>>,
}
impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
fn from(vid: ty::RegionVid) -> Self {
RegionVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
type Value = UnifiedRegion<'tcx>;
#[inline]
fn index(&self) -> u32 {
self.vid.as_u32()
}
#[inline]
fn from_index(i: u32) -> Self {
RegionVidKey::from(ty::RegionVid::from_u32(i))
}
fn tag() -> &'static str {
"RegionVidKey"
}
}
impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
type Error = NoError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
// We pick the value of the least universe because it is compatible with more variables.
// This is *not* necessary for completeness.
#[cold]
fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> {
cmp::min_by_key(r1, r2, |r| match r.kind() {
ty::ReStatic
| ty::ReErased
| ty::ReLateParam(..)
| ty::ReEarlyParam(..)
| ty::ReError(_) => ty::UniverseIndex::ROOT,
ty::RePlaceholder(placeholder) => placeholder.universe,
ty::ReVar(..) | ty::ReBound(..) => bug!("not a universal region"),
})
}
Ok(match (value1.value, value2.value) {
// Here we can just pick one value, because the full constraints graph
// will be handled later. Ideally, we might want a `MultipleValues`
// variant or something. For now though, this is fine.
(Some(val1), Some(val2)) => Self { value: Some(min_universe(val1, val2)) },
(Some(_), _) => *value1,
(_, Some(_)) => *value2,
(None, None) => *value1,
})
}
}
impl ToType for ty::IntVarValue {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
ty::IntType(i) => Ty::new_int(tcx, i),
ty::UintType(i) => Ty::new_uint(tcx, i),
}
}
}
impl ToType for ty::FloatVarValue {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
Ty::new_float(tcx, self.0)
}
}
// Generic consts.
#[derive(Copy, Clone, Debug)]
pub struct ConstVariableOrigin {
pub kind: ConstVariableOriginKind,
pub span: Span,
}
/// Reasons to create a const inference variable
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableOriginKind {
MiscVariable,
ConstInference,
ConstParameterDefinition(Symbol, DefId),
}
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
Known { value: ty::Const<'tcx> },
Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
}
impl<'tcx> ConstVariableValue<'tcx> {
/// If this value is known, returns the const it is known to be.
/// Otherwise, `None`.
pub fn known(&self) -> Option<ty::Const<'tcx>> {
match *self {
ConstVariableValue::Unknown { .. } => None,
ConstVariableValue::Known { value } => Some(value),
}
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct ConstVidKey<'tcx> {
pub vid: ty::ConstVid,
pub phantom: PhantomData<ty::Const<'tcx>>,
}
impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
fn from(vid: ty::ConstVid) -> Self {
ConstVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
type Value = ConstVariableValue<'tcx>;
#[inline]
fn index(&self) -> u32 {
self.vid.as_u32()
}
#[inline]
fn from_index(i: u32) -> Self {
ConstVidKey::from(ty::ConstVid::from_u32(i))
}
fn tag() -> &'static str {
"ConstVidKey"
}
}
impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
type Error = NoError;
fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
match (value1, value2) {
(ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
bug!("equating two const variables, both of which have known values")
}
// If one side is known, prefer that one.
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
// If both sides are *unknown*, it hardly matters, does it?
(
ConstVariableValue::Unknown { origin, universe: universe1 },
ConstVariableValue::Unknown { origin: _, universe: universe2 },
) => {
// If we unify two unbound variables, ?T and ?U, then whatever
// value they wind up taking (which must be the same value) must
// be nameable by both universes. Therefore, the resulting
// universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope.
let universe = cmp::min(universe1, universe2);
Ok(ConstVariableValue::Unknown { origin, universe })
}
}
}
}
/// 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")
}
}
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct EffectVidKey<'tcx> {
pub vid: ty::EffectVid,
pub phantom: PhantomData<EffectVarValue<'tcx>>,
}
impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
fn from(vid: ty::EffectVid) -> Self {
EffectVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
type Value = Option<EffectVarValue<'tcx>>;
#[inline]
fn index(&self) -> u32 {
self.vid.as_u32()
}
#[inline]
fn from_index(i: u32) -> Self {
EffectVidKey::from(ty::EffectVid::from_u32(i))
}
fn tag() -> &'static str {
"EffectVidKey"
}
}