use chalk_ir::cast::Cast;
use chalk_ir::interner::Interner;
use chalk_ir::*;
use ena::unify::{UnifyKey, UnifyValue};
use std::cmp::min;
use std::fmt;
use std::marker::PhantomData;
use std::u32;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EnaVariable<I: Interner> {
var: InferenceVar,
phantom: PhantomData<I>,
}
impl<I: Interner> From<InferenceVar> for EnaVariable<I> {
fn from(var: InferenceVar) -> EnaVariable<I> {
EnaVariable {
var,
phantom: PhantomData,
}
}
}
impl<I: Interner> From<EnaVariable<I>> for InferenceVar {
fn from(ena_var: EnaVariable<I>) -> InferenceVar {
ena_var.var
}
}
impl<I: Interner> EnaVariable<I> {
pub fn to_ty_with_kind(self, interner: I, kind: TyVariableKind) -> Ty<I> {
self.var.to_ty(interner, kind)
}
pub fn to_ty(self, interner: I) -> Ty<I> {
self.var.to_ty(interner, TyVariableKind::General)
}
pub fn to_lifetime(self, interner: I) -> Lifetime<I> {
self.var.to_lifetime(interner)
}
pub fn to_const(self, interner: I, ty: Ty<I>) -> Const<I> {
self.var.to_const(interner, ty)
}
}
impl<I: Interner> UnifyKey for EnaVariable<I> {
type Value = InferenceValue<I>;
fn index(&self) -> u32 {
self.var.index()
}
fn from_index(u: u32) -> Self {
EnaVariable::from(InferenceVar::from(u))
}
fn tag() -> &'static str {
"EnaVariable"
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InferenceValue<I: Interner> {
Unbound(UniverseIndex),
Bound(GenericArg<I>),
}
impl<I: Interner> InferenceValue<I> {
pub fn from_ty(interner: I, ty: Ty<I>) -> Self {
InferenceValue::Bound(ty.cast(interner))
}
pub fn from_lifetime(interner: I, lifetime: Lifetime<I>) -> Self {
InferenceValue::Bound(lifetime.cast(interner))
}
pub fn from_const(interner: I, constant: Const<I>) -> Self {
InferenceValue::Bound(constant.cast(interner))
}
}
impl<I: Interner> UnifyValue for InferenceValue<I> {
type Error = (InferenceValue<I>, InferenceValue<I>);
fn unify_values(
a: &InferenceValue<I>,
b: &InferenceValue<I>,
) -> Result<InferenceValue<I>, (InferenceValue<I>, InferenceValue<I>)> {
match (a, b) {
(&InferenceValue::Unbound(ui_a), &InferenceValue::Unbound(ui_b)) => {
Ok(InferenceValue::Unbound(min(ui_a, ui_b)))
}
(bound @ &InferenceValue::Bound(_), &InferenceValue::Unbound(_))
| (&InferenceValue::Unbound(_), bound @ &InferenceValue::Bound(_)) => Ok(bound.clone()),
(&InferenceValue::Bound(_), &InferenceValue::Bound(_)) => {
panic!("we should not be asked to unify two bound things")
}
}
}
}
impl<I: Interner> fmt::Debug for EnaVariable<I> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.var)
}
}