cairo_lang_sierra/extensions/
types.rsuse super::args_as_single_type;
use super::error::{ExtensionError, SpecializationError};
use super::type_specialization_context::TypeSpecializationContext;
use crate::ids::{ConcreteTypeId, GenericTypeId};
use crate::program::{ConcreteTypeLongId, GenericArg};
pub trait GenericType: Sized {
type Concrete: ConcreteType;
fn by_id(id: &GenericTypeId) -> Option<Self>;
fn specialize(
&self,
context: &dyn TypeSpecializationContext,
args: &[GenericArg],
) -> Result<Self::Concrete, SpecializationError>;
}
pub trait GenericTypeEx: GenericType {
fn specialize_by_id(
context: &dyn TypeSpecializationContext,
type_id: &GenericTypeId,
args: &[GenericArg],
) -> Result<Self::Concrete, ExtensionError>;
}
impl<TGenericType: GenericType> GenericTypeEx for TGenericType {
fn specialize_by_id(
context: &dyn TypeSpecializationContext,
type_id: &GenericTypeId,
args: &[GenericArg],
) -> Result<TGenericType::Concrete, ExtensionError> {
Self::by_id(type_id)
.ok_or_else(move || ExtensionError::TypeSpecialization {
type_id: type_id.clone(),
error: SpecializationError::UnsupportedId(type_id.0.clone()),
})?
.specialize(context, args)
.map_err(move |error| ExtensionError::TypeSpecialization {
type_id: type_id.clone(),
error,
})
}
}
pub trait NamedType: Default {
type Concrete: ConcreteType;
const ID: GenericTypeId;
fn id() -> GenericTypeId {
Self::ID
}
fn concrete_type_long_id(generic_args: &[GenericArg]) -> ConcreteTypeLongId {
ConcreteTypeLongId { generic_id: Self::id(), generic_args: generic_args.to_vec() }
}
fn specialize(
&self,
context: &dyn TypeSpecializationContext,
args: &[GenericArg],
) -> Result<Self::Concrete, SpecializationError>;
}
impl<TNamedType: NamedType> GenericType for TNamedType {
type Concrete = <Self as NamedType>::Concrete;
fn by_id(id: &GenericTypeId) -> Option<Self> {
if &Self::ID == id { Some(Self::default()) } else { None }
}
fn specialize(
&self,
context: &dyn TypeSpecializationContext,
args: &[GenericArg],
) -> Result<Self::Concrete, SpecializationError> {
<Self as NamedType>::specialize(self, context, args)
}
}
pub trait NoGenericArgsGenericType: Default {
const ID: GenericTypeId;
const STORABLE: bool;
const DUPLICATABLE: bool;
const DROPPABLE: bool;
const ZERO_SIZED: bool;
}
impl<T: NoGenericArgsGenericType> NamedType for T {
type Concrete = InfoOnlyConcreteType;
const ID: GenericTypeId = <Self as NoGenericArgsGenericType>::ID;
fn specialize(
&self,
_context: &dyn TypeSpecializationContext,
args: &[GenericArg],
) -> Result<Self::Concrete, SpecializationError> {
if args.is_empty() {
Ok(Self::Concrete {
info: TypeInfo {
long_id: Self::concrete_type_long_id(args),
storable: T::STORABLE,
droppable: T::DROPPABLE,
duplicatable: T::DUPLICATABLE,
zero_sized: T::ZERO_SIZED,
},
})
} else {
Err(SpecializationError::WrongNumberOfGenericArgs)
}
}
}
pub trait GenericTypeArgGenericType: Default {
const ID: GenericTypeId;
fn calc_info(
&self,
context: &dyn TypeSpecializationContext,
long_id: ConcreteTypeLongId,
wrapped_info: TypeInfo,
) -> Result<TypeInfo, SpecializationError>;
}
#[derive(Default)]
pub struct GenericTypeArgGenericTypeWrapper<T: GenericTypeArgGenericType>(T);
impl<T: GenericTypeArgGenericType> NamedType for GenericTypeArgGenericTypeWrapper<T> {
type Concrete = InfoAndTypeConcreteType;
const ID: GenericTypeId = T::ID;
fn specialize(
&self,
context: &dyn TypeSpecializationContext,
args: &[GenericArg],
) -> Result<Self::Concrete, SpecializationError> {
let ty = args_as_single_type(args)?;
let long_id = Self::concrete_type_long_id(args);
let wrapped_info = context.get_type_info(ty.clone())?;
Ok(Self::Concrete { info: self.0.calc_info(context, long_id, wrapped_info)?, ty })
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TypeInfo {
pub long_id: ConcreteTypeLongId,
pub storable: bool,
pub droppable: bool,
pub duplicatable: bool,
pub zero_sized: bool,
}
pub trait ConcreteType {
fn info(&self) -> &TypeInfo;
}
pub struct InfoOnlyConcreteType {
pub info: TypeInfo,
}
impl ConcreteType for InfoOnlyConcreteType {
fn info(&self) -> &TypeInfo {
&self.info
}
}
pub struct InfoAndTypeConcreteType {
pub info: TypeInfo,
pub ty: ConcreteTypeId,
}
impl ConcreteType for InfoAndTypeConcreteType {
fn info(&self) -> &TypeInfo {
&self.info
}
}
#[macro_export]
macro_rules! define_type_hierarchy {
(pub enum $name:ident { $($variant_name:ident ($variant:ty),)* },
$concrete_name:ident) => {
#[allow(clippy::enum_variant_names)]
pub enum $name {
$($variant_name ($variant)),*
}
impl $crate::extensions::types::GenericType for $name {
type Concrete = $concrete_name;
fn by_id(id: &$crate::ids::GenericTypeId) -> Option<Self> {
$(
if let Some(res) = <$variant>::by_id(id){
return Some(Self::$variant_name(res));
}
)*
None
}
fn specialize(
&self,
context: &dyn $crate::extensions::type_specialization_context::TypeSpecializationContext,
args: &[$crate::program::GenericArg]
) -> Result<Self::Concrete, $crate::extensions::SpecializationError>{
match self {
$(
Self::$variant_name(value) => {
Ok(Self::Concrete::$variant_name(
<$variant as $crate::extensions::GenericType>::specialize(
value, context, args,
)?
.into(),
))
}
),*
}
}
}
pub enum $concrete_name {
$($variant_name (<$variant as $crate::extensions::GenericType> ::Concrete),)*
}
impl $crate::extensions::ConcreteType for $concrete_name {
fn info(&self) -> &$crate::extensions::types::TypeInfo {
match self {
$(Self::$variant_name(value) => value.info()),*
}
}
}
}
}