cairo_lang_sierra_generator/
db.rs1use std::sync::Arc;
2
3use cairo_lang_diagnostics::Maybe;
4use cairo_lang_filesystem::flag::flag_unsafe_panic;
5use cairo_lang_filesystem::ids::CrateId;
6use cairo_lang_lowering::db::LoweringGroup;
7use cairo_lang_lowering::panic::PanicSignatureInfo;
8use cairo_lang_sierra::extensions::lib_func::SierraApChange;
9use cairo_lang_sierra::extensions::{ConcreteType, GenericTypeEx};
10use cairo_lang_sierra::ids::ConcreteTypeId;
11use cairo_lang_utils::{LookupIntern, Upcast};
12use lowering::ids::ConcreteFunctionWithBodyId;
13use {cairo_lang_lowering as lowering, cairo_lang_semantic as semantic};
14
15use crate::program_generator::{self, SierraProgramWithDebug};
16use crate::replace_ids::SierraIdReplacer;
17use crate::specialization_context::SierraSignatureSpecializationContext;
18use crate::types::cycle_breaker_info;
19use crate::{ap_change, function_generator, pre_sierra, replace_ids};
20
21#[derive(Clone, Debug, PartialEq, Eq, Hash)]
24pub enum SierraGeneratorTypeLongId {
25 Regular(Arc<cairo_lang_sierra::program::ConcreteTypeLongId>),
27 CycleBreaker(semantic::TypeId),
29 Phantom(semantic::TypeId),
32}
33
34#[salsa::query_group(SierraGenDatabase)]
35pub trait SierraGenGroup: LoweringGroup + Upcast<dyn LoweringGroup> {
36 #[salsa::interned]
37 fn intern_label_id(&self, id: pre_sierra::LabelLongId) -> pre_sierra::LabelId;
38
39 #[salsa::interned]
40 fn intern_concrete_lib_func(
41 &self,
42 id: cairo_lang_sierra::program::ConcreteLibfuncLongId,
43 ) -> cairo_lang_sierra::ids::ConcreteLibfuncId;
44
45 #[salsa::interned]
46 fn intern_concrete_type(
47 &self,
48 id: SierraGeneratorTypeLongId,
49 ) -> cairo_lang_sierra::ids::ConcreteTypeId;
50
51 #[salsa::interned]
55 fn intern_sierra_function(
56 &self,
57 id: lowering::ids::FunctionId,
58 ) -> cairo_lang_sierra::ids::FunctionId;
59
60 #[salsa::invoke(crate::types::get_concrete_type_id)]
62 fn get_concrete_type_id(
63 &self,
64 type_id: semantic::TypeId,
65 ) -> Maybe<cairo_lang_sierra::ids::ConcreteTypeId>;
66
67 #[salsa::invoke(crate::types::get_index_enum_type_id)]
69 fn get_index_enum_type_id(
70 &self,
71 index_count: usize,
72 ) -> Maybe<cairo_lang_sierra::ids::ConcreteTypeId>;
73
74 #[salsa::invoke(crate::types::get_concrete_long_type_id)]
76 fn get_concrete_long_type_id(
77 &self,
78 type_id: semantic::TypeId,
79 ) -> Maybe<Arc<cairo_lang_sierra::program::ConcreteTypeLongId>>;
80
81 #[salsa::invoke(crate::types::is_self_referential)]
83 fn is_self_referential(&self, type_id: semantic::TypeId) -> Maybe<bool>;
84
85 #[salsa::invoke(crate::types::type_dependencies)]
90 fn type_dependencies(&self, type_id: semantic::TypeId) -> Maybe<Arc<[semantic::TypeId]>>;
91
92 #[salsa::invoke(crate::types::has_in_deps)]
93 #[salsa::cycle(crate::types::has_in_deps_cycle)]
94 fn has_in_deps(&self, type_id: semantic::TypeId, needle: semantic::TypeId) -> Maybe<bool>;
95
96 fn get_function_signature(
99 &self,
100 function_id: cairo_lang_sierra::ids::FunctionId,
101 ) -> Maybe<Arc<cairo_lang_sierra::program::FunctionSignature>>;
102
103 fn get_type_info(
105 &self,
106 concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
107 ) -> Maybe<Arc<cairo_lang_sierra::extensions::types::TypeInfo>>;
108
109 #[salsa::invoke(function_generator::priv_function_with_body_sierra_data)]
111 fn priv_function_with_body_sierra_data(
112 &self,
113 function_id: ConcreteFunctionWithBodyId,
114 ) -> function_generator::SierraFunctionWithBodyData;
115 #[salsa::invoke(function_generator::function_with_body_sierra)]
117 fn function_with_body_sierra(
118 &self,
119 function_id: ConcreteFunctionWithBodyId,
120 ) -> Maybe<Arc<pre_sierra::Function>>;
121
122 #[salsa::invoke(function_generator::priv_get_dummy_function)]
124 fn priv_get_dummy_function(
125 &self,
126 function_id: ConcreteFunctionWithBodyId,
127 ) -> Maybe<Arc<pre_sierra::Function>>;
128
129 #[salsa::invoke(ap_change::get_ap_change)]
132 fn get_ap_change(&self, function_id: ConcreteFunctionWithBodyId) -> Maybe<SierraApChange>;
133
134 #[salsa::invoke(program_generator::get_sierra_program_for_functions)]
136 fn get_sierra_program_for_functions(
137 &self,
138 requested_function_ids: Vec<ConcreteFunctionWithBodyId>,
139 ) -> Maybe<Arc<SierraProgramWithDebug>>;
140
141 #[salsa::invoke(program_generator::get_sierra_program)]
143 fn get_sierra_program(
144 &self,
145 requested_crate_ids: Vec<CrateId>,
146 ) -> Maybe<Arc<SierraProgramWithDebug>>;
147}
148
149fn get_function_signature(
150 db: &dyn SierraGenGroup,
151 function_id: cairo_lang_sierra::ids::FunctionId,
152) -> Maybe<Arc<cairo_lang_sierra::program::FunctionSignature>> {
153 let lowered_function_id = function_id.lookup_intern(db);
159 let signature = lowered_function_id.signature(db)?;
160
161 let implicits = db
162 .function_implicits(lowered_function_id)?
163 .iter()
164 .map(|ty| db.get_concrete_type_id(*ty))
165 .collect::<Maybe<Vec<ConcreteTypeId>>>()?;
166
167 let mut all_params = implicits.clone();
169 let mut extra_rets = vec![];
170 for param in &signature.params {
171 let concrete_type_id = db.get_concrete_type_id(param.ty())?;
172 all_params.push(concrete_type_id.clone());
173 }
174 for var in &signature.extra_rets {
175 let concrete_type_id = db.get_concrete_type_id(var.ty())?;
176 extra_rets.push(concrete_type_id);
177 }
178
179 let mut ret_types = implicits;
180
181 let may_panic = !flag_unsafe_panic(db) && db.function_may_panic(lowered_function_id)?;
182 if may_panic {
183 let panic_info = PanicSignatureInfo::new(db, &signature);
184 ret_types.push(db.get_concrete_type_id(panic_info.actual_return_ty)?);
185 } else {
186 ret_types.extend(extra_rets);
187 if !signature.return_type.is_unit(db) {
189 ret_types.push(db.get_concrete_type_id(signature.return_type)?);
190 }
191 }
192
193 Ok(Arc::new(cairo_lang_sierra::program::FunctionSignature {
194 param_types: all_params,
195 ret_types,
196 }))
197}
198
199fn get_type_info(
200 db: &dyn SierraGenGroup,
201 concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
202) -> Maybe<Arc<cairo_lang_sierra::extensions::types::TypeInfo>> {
203 let long_id = match concrete_type_id.lookup_intern(db) {
204 SierraGeneratorTypeLongId::Regular(long_id) => long_id,
205 SierraGeneratorTypeLongId::CycleBreaker(ty) => {
206 let info = cycle_breaker_info(db, ty)?;
207 return Ok(Arc::new(cairo_lang_sierra::extensions::types::TypeInfo {
208 long_id: db.get_concrete_long_type_id(ty)?.as_ref().clone(),
209 storable: true,
210 droppable: info.droppable,
211 duplicatable: info.duplicatable,
212 zero_sized: false,
213 }));
214 }
215 SierraGeneratorTypeLongId::Phantom(ty) => {
216 let long_id = db.get_concrete_long_type_id(ty)?.as_ref().clone();
217 return Ok(Arc::new(cairo_lang_sierra::extensions::types::TypeInfo {
218 long_id,
219 storable: false,
220 droppable: false,
221 duplicatable: false,
222 zero_sized: true,
223 }));
224 }
225 };
226 let concrete_ty = cairo_lang_sierra::extensions::core::CoreType::specialize_by_id(
227 &SierraSignatureSpecializationContext(db),
228 &long_id.generic_id,
229 &long_id.generic_args,
230 )
231 .unwrap_or_else(|err| {
232 let mut long_id = long_id.as_ref().clone();
233 replace_ids::DebugReplacer { db }.replace_generic_args(&mut long_id.generic_args);
234 panic!("Got failure while specializing type `{long_id}`: {err}")
235 });
236 Ok(Arc::new(concrete_ty.info().clone()))
237}
238
239pub fn sierra_concrete_long_id(
241 db: &dyn SierraGenGroup,
242 concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
243) -> Maybe<Arc<cairo_lang_sierra::program::ConcreteTypeLongId>> {
244 match concrete_type_id.lookup_intern(db) {
245 SierraGeneratorTypeLongId::Regular(long_id) => Ok(long_id),
246 SierraGeneratorTypeLongId::Phantom(type_id)
247 | SierraGeneratorTypeLongId::CycleBreaker(type_id) => db.get_concrete_long_type_id(type_id),
248 }
249}