use super::{TypeBuilder, WithSelf};
use crate::{
error::Result,
metadata::{
drop_overrides::DropOverridesMeta, dup_overrides::DupOverridesMeta,
enum_snapshot_variants::EnumSnapshotVariantsMeta, MetadataStorage,
},
utils::ProgramRegistryExt,
};
use cairo_lang_sierra::{
extensions::{
core::{CoreLibfunc, CoreType},
types::InfoAndTypeConcreteType,
},
program_registry::ProgramRegistry,
};
use melior::{
dialect::func,
helpers::BuiltinBlockExt,
ir::{Block, BlockLike, Location, Module, Region, Type},
Context,
};
pub fn build<'ctx>(
context: &'ctx Context,
module: &Module<'ctx>,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
metadata: &mut MetadataStorage,
info: WithSelf<InfoAndTypeConcreteType>,
) -> Result<Type<'ctx>> {
if let Some(variants) = registry.get_type(&info.ty)?.variants() {
metadata
.get_or_insert_with(EnumSnapshotVariantsMeta::default)
.set_mapping(info.self_ty, variants);
}
DupOverridesMeta::register_with(
context,
module,
registry,
metadata,
info.self_ty(),
|metadata| {
registry.build_type(context, module, metadata, &info.ty)?;
DupOverridesMeta::is_overriden(metadata, &info.ty)
.then(|| build_dup(context, module, registry, metadata, &info))
.transpose()
},
)?;
DropOverridesMeta::register_with(
context,
module,
registry,
metadata,
info.self_ty(),
|metadata| {
registry.build_type(context, module, metadata, &info.ty)?;
DropOverridesMeta::is_overriden(metadata, &info.ty)
.then(|| build_drop(context, module, registry, metadata, &info))
.transpose()
},
)?;
registry.build_type(context, module, metadata, &info.ty)
}
fn build_dup<'ctx>(
context: &'ctx Context,
module: &Module<'ctx>,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
metadata: &mut MetadataStorage,
info: &WithSelf<InfoAndTypeConcreteType>,
) -> Result<Region<'ctx>> {
let location = Location::unknown(context);
let inner_ty = registry.build_type(context, module, metadata, &info.ty)?;
let region = Region::new();
let entry = region.append_block(Block::new(&[(inner_ty, location)]));
let values = DupOverridesMeta::invoke_override(
context,
registry,
module,
&entry,
&entry,
location,
metadata,
&info.ty,
entry.arg(0)?,
)?;
entry.append_operation(func::r#return(&[values.0, values.1], location));
Ok(region)
}
fn build_drop<'ctx>(
context: &'ctx Context,
module: &Module<'ctx>,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
metadata: &mut MetadataStorage,
info: &WithSelf<InfoAndTypeConcreteType>,
) -> Result<Region<'ctx>> {
let location = Location::unknown(context);
let inner_ty = registry.build_type(context, module, metadata, &info.ty)?;
let region = Region::new();
let entry = region.append_block(Block::new(&[(inner_ty, location)]));
DropOverridesMeta::invoke_override(
context,
registry,
module,
&entry,
&entry,
location,
metadata,
&info.ty,
entry.arg(0)?,
)?;
entry.append_operation(func::r#return(&[], location));
Ok(region)
}