use std::sync::Arc;
use cairo_lang_diagnostics::Maybe;
use cairo_lang_filesystem::ids::CrateId;
use cairo_lang_lowering::db::LoweringGroup;
use cairo_lang_lowering::panic::PanicSignatureInfo;
use cairo_lang_sierra::extensions::lib_func::SierraApChange;
use cairo_lang_sierra::extensions::{ConcreteType, GenericTypeEx};
use cairo_lang_sierra::ids::ConcreteTypeId;
use cairo_lang_utils::Upcast;
use lowering::ids::ConcreteFunctionWithBodyId;
use semantic::items::imp::ImplLookupContext;
use {cairo_lang_lowering as lowering, cairo_lang_semantic as semantic};
use crate::program_generator::{self};
use crate::specialization_context::SierraSignatureSpecializationContext;
use crate::{ap_change, function_generator, pre_sierra};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum SierraGeneratorTypeLongId {
Regular(Arc<cairo_lang_sierra::program::ConcreteTypeLongId>),
CycleBreaker(semantic::TypeId),
}
#[salsa::query_group(SierraGenDatabase)]
pub trait SierraGenGroup: LoweringGroup + Upcast<dyn LoweringGroup> {
#[salsa::interned]
fn intern_label_id(&self, id: pre_sierra::LabelLongId) -> pre_sierra::LabelId;
#[salsa::interned]
fn intern_concrete_lib_func(
&self,
id: cairo_lang_sierra::program::ConcreteLibfuncLongId,
) -> cairo_lang_sierra::ids::ConcreteLibfuncId;
#[salsa::interned]
fn intern_concrete_type(
&self,
id: SierraGeneratorTypeLongId,
) -> cairo_lang_sierra::ids::ConcreteTypeId;
#[salsa::interned]
fn intern_sierra_function(
&self,
id: lowering::ids::FunctionId,
) -> cairo_lang_sierra::ids::FunctionId;
#[salsa::invoke(crate::types::get_concrete_type_id)]
fn get_concrete_type_id(
&self,
type_id: semantic::TypeId,
) -> Maybe<cairo_lang_sierra::ids::ConcreteTypeId>;
#[salsa::invoke(crate::types::get_concrete_long_type_id)]
fn get_concrete_long_type_id(
&self,
type_id: semantic::TypeId,
) -> Maybe<Arc<cairo_lang_sierra::program::ConcreteTypeLongId>>;
#[salsa::invoke(crate::types::is_self_referential)]
#[salsa::cycle(crate::types::is_self_referential_cycle)]
fn is_self_referential(&self, type_id: semantic::TypeId) -> Maybe<bool>;
#[salsa::invoke(crate::types::type_dependencies)]
fn type_dependencies(&self, type_id: semantic::TypeId) -> Maybe<Arc<Vec<semantic::TypeId>>>;
fn get_function_signature(
&self,
function_id: cairo_lang_sierra::ids::FunctionId,
) -> Maybe<Arc<cairo_lang_sierra::program::FunctionSignature>>;
fn get_type_info(
&self,
concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
) -> Maybe<Arc<cairo_lang_sierra::extensions::types::TypeInfo>>;
#[salsa::invoke(function_generator::priv_function_with_body_sierra_data)]
fn priv_function_with_body_sierra_data(
&self,
function_id: ConcreteFunctionWithBodyId,
) -> function_generator::SierraFunctionWithBodyData;
#[salsa::invoke(function_generator::function_with_body_sierra)]
fn function_with_body_sierra(
&self,
function_id: ConcreteFunctionWithBodyId,
) -> Maybe<Arc<pre_sierra::Function>>;
#[salsa::invoke(ap_change::get_ap_change)]
fn get_ap_change(&self, function_id: ConcreteFunctionWithBodyId) -> Maybe<SierraApChange>;
#[salsa::invoke(program_generator::get_sierra_program_for_functions)]
fn get_sierra_program_for_functions(
&self,
requested_function_ids: Vec<ConcreteFunctionWithBodyId>,
) -> Maybe<Arc<cairo_lang_sierra::program::Program>>;
#[salsa::invoke(program_generator::get_sierra_program)]
fn get_sierra_program(
&self,
requested_crate_ids: Vec<CrateId>,
) -> Maybe<Arc<cairo_lang_sierra::program::Program>>;
}
fn get_function_signature(
db: &dyn SierraGenGroup,
function_id: cairo_lang_sierra::ids::FunctionId,
) -> Maybe<Arc<cairo_lang_sierra::program::FunctionSignature>> {
let lowered_function_id = db.lookup_intern_sierra_function(function_id);
let signature = lowered_function_id.signature(db.upcast())?;
let may_panic = db.function_may_panic(lowered_function_id)?;
let implicits = db
.function_implicits(lowered_function_id)?
.iter()
.map(|ty| db.get_concrete_type_id(*ty))
.collect::<Maybe<Vec<ConcreteTypeId>>>()?;
let mut all_params = implicits.clone();
let mut extra_rets = vec![];
for param in &signature.params {
let concrete_type_id = db.get_concrete_type_id(param.ty())?;
all_params.push(concrete_type_id.clone());
}
for var in &signature.extra_rets {
let concrete_type_id = db.get_concrete_type_id(var.ty())?;
extra_rets.push(concrete_type_id);
}
let mut ret_types = implicits;
if may_panic {
let panic_info = PanicSignatureInfo::new(db.upcast(), &signature);
ret_types.push(db.get_concrete_type_id(panic_info.panic_ty)?);
} else {
ret_types.extend(extra_rets.into_iter());
ret_types.push(db.get_concrete_type_id(signature.return_type)?);
}
Ok(Arc::new(cairo_lang_sierra::program::FunctionSignature {
param_types: all_params,
ret_types,
}))
}
fn get_type_info(
db: &dyn SierraGenGroup,
concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
) -> Maybe<Arc<cairo_lang_sierra::extensions::types::TypeInfo>> {
let long_id = match db.lookup_intern_concrete_type(concrete_type_id) {
SierraGeneratorTypeLongId::Regular(long_id) => long_id,
SierraGeneratorTypeLongId::CycleBreaker(ty) => {
let long_id = db.get_concrete_long_type_id(ty)?.as_ref().clone();
let info = db.type_info(
ImplLookupContext { modules: [].into_iter().collect(), generic_params: vec![] },
ty,
)?;
return Ok(Arc::new(cairo_lang_sierra::extensions::types::TypeInfo {
long_id,
storable: true,
droppable: info.droppable.is_ok(),
duplicatable: info.duplicatable.is_ok(),
zero_sized: false,
}));
}
};
let concrete_ty = cairo_lang_sierra::extensions::core::CoreType::specialize_by_id(
&SierraSignatureSpecializationContext(db),
&long_id.generic_id,
&long_id.generic_args,
)
.expect("Got failure while specializing type.");
Ok(Arc::new(concrete_ty.info().clone()))
}
pub fn sierra_concrete_long_id(
db: &dyn SierraGenGroup,
concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
) -> Maybe<Arc<cairo_lang_sierra::program::ConcreteTypeLongId>> {
match db.lookup_intern_concrete_type(concrete_type_id) {
SierraGeneratorTypeLongId::Regular(long_id) => Ok(long_id),
SierraGeneratorTypeLongId::CycleBreaker(type_id) => db.get_concrete_long_type_id(type_id),
}
}