rustc_middle/infer/
unify_key.rsuse std::cmp;
use std::marker::PhantomData;
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use crate::ty::{self, Ty, TyCtxt};
pub trait ToType {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
}
#[derive(Copy, Clone, Debug)]
pub enum RegionVariableValue<'tcx> {
Known { value: ty::Region<'tcx> },
Unknown { universe: ty::UniverseIndex },
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey<'tcx> {
pub vid: ty::RegionVid,
pub phantom: PhantomData<RegionVariableValue<'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 = RegionVariableValue<'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"
}
}
pub struct RegionUnificationError;
impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
type Error = RegionUnificationError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
match (*value1, *value2) {
(RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => {
Err(RegionUnificationError)
}
(RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe })
| (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => {
let universe_of_value = match value.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"),
};
if universe.can_name(universe_of_value) {
Ok(RegionVariableValue::Known { value })
} else {
Err(RegionUnificationError)
}
}
(
RegionVariableValue::Unknown { universe: a },
RegionVariableValue::Unknown { universe: b },
) => {
Ok(RegionVariableValue::Unknown { universe: a.min(b) })
}
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ConstVariableOrigin {
pub span: Span,
pub param_def_id: Option<DefId>,
}
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
Known { value: ty::Const<'tcx> },
Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
}
impl<'tcx> ConstVariableValue<'tcx> {
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")
}
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
(
ConstVariableValue::Unknown { origin, universe: universe1 },
ConstVariableValue::Unknown { origin: _, universe: universe2 },
) => {
let universe = cmp::min(universe1, universe2);
Ok(ConstVariableValue::Unknown { origin, universe })
}
}
}
}