use midenc_hir::{Immediate, SourceSpan, Type, ValueRef};
use midenc_session::diagnostics::{miette, Diagnostic};
#[derive(Debug, thiserror::Error, Diagnostic)]
pub enum InvalidCastError {
#[error("cannot cast an immediate to a value of type {0}")]
#[diagnostic()]
UnsupportedType(Type),
#[error("failed to cast {value} to type {ty}: value is out of range for type")]
#[diagnostic()]
InvalidBitcast { value: Immediate, ty: Type },
}
#[derive(Debug, Copy, Clone)]
pub enum Value {
Poison {
origin: SourceSpan,
used: SourceSpan,
value: Immediate,
},
Immediate(Immediate),
}
impl Value {
pub fn poison(span: SourceSpan, value: impl Into<Immediate>) -> Self {
Self::Poison {
origin: span,
used: SourceSpan::UNKNOWN,
value: value.into(),
}
}
pub fn ty(&self) -> Type {
match self {
Self::Poison { value, .. } | Self::Immediate(value) => value.ty(),
}
}
pub fn map_ty(self, ty: &Type) -> Result<Self, InvalidCastError> {
match self {
Self::Poison {
origin,
used,
value,
} => {
let value = Self::cast_immediate(value, ty)?;
Ok(Self::Poison {
origin,
used,
value,
})
}
Self::Immediate(value) => Self::cast_immediate(value, ty).map(Self::Immediate),
}
}
pub fn cast_immediate(value: Immediate, ty: &Type) -> Result<Immediate, InvalidCastError> {
let result = match ty {
Type::I1 => value.as_bool().map(Immediate::I1),
Type::I8 => value.bitcast_i8().map(Immediate::I8),
Type::U8 => value.bitcast_u8().map(Immediate::U8),
Type::I16 => value.bitcast_i16().map(Immediate::I16),
Type::U16 => value.bitcast_u16().map(Immediate::U16),
Type::I32 => value.bitcast_i32().map(Immediate::I32),
Type::U32 => value.bitcast_u32().map(Immediate::U32),
Type::I64 => value.bitcast_i64().map(Immediate::I64),
Type::U64 => value.bitcast_u64().map(Immediate::U64),
Type::I128 => value.bitcast_i128().map(Immediate::I128),
Type::U128 => value.bitcast_u128().map(Immediate::U128),
Type::Felt => value.bitcast_felt().map(Immediate::Felt),
Type::F64 => value.bitcast_f64().map(Immediate::F64),
Type::Ptr(_) => value.bitcast_u32().map(Immediate::U32),
ty => return Err(InvalidCastError::UnsupportedType(ty.clone())),
};
result.ok_or_else(|| InvalidCastError::InvalidBitcast {
value,
ty: ty.clone(),
})
}
}
impl Eq for Value {}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Poison { value: x, .. }, Self::Poison { value: y, .. }) => x == y,
(Self::Poison { .. }, _) | (_, Self::Poison { .. }) => false,
(Self::Immediate(x), Self::Immediate(y)) => x == y,
}
}
}
impl core::fmt::Display for Value {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Poison { .. } => f.write_str("poison"),
Self::Immediate(imm) => write!(f, "{imm}"),
}
}
}
impl<T: Into<Immediate>> From<T> for Value {
fn from(value: T) -> Self {
Self::Immediate(value.into())
}
}
pub struct MaterializedValue {
pub id: ValueRef,
pub value: Value,
}
impl core::fmt::Display for MaterializedValue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} = {}", &self.id, &self.value)
}
}