cairo_lang_sierra_generator/
db.rs1use std::sync::Arc;
2
3use cairo_lang_diagnostics::{Maybe, MaybeAsRef};
4use cairo_lang_filesystem::flag::flag_unsafe_panic;
5use cairo_lang_filesystem::ids::{CrateId, Tracked};
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 lowering::ids::ConcreteFunctionWithBodyId;
12use salsa::plumbing::FromId;
13use salsa::{Database, Id};
14use {cairo_lang_lowering as lowering, cairo_lang_semantic as semantic};
15
16use crate::program_generator::{self, SierraProgramWithDebug};
17use crate::replace_ids::SierraIdReplacer;
18use crate::specialization_context::SierraSignatureSpecializationContext;
19use crate::types::cycle_breaker_info;
20use crate::{ap_change, function_generator, pre_sierra, replace_ids};
21
22#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
25pub enum SierraGeneratorTypeLongId<'db> {
26 Regular(Arc<cairo_lang_sierra::program::ConcreteTypeLongId>),
28 CycleBreaker(semantic::TypeId<'db>),
30 Phantom(semantic::TypeId<'db>),
33}
34
35#[salsa::interned(revisions = usize::MAX)]
37struct ConcreteLibfuncIdLongWrapper {
38 id: cairo_lang_sierra::program::ConcreteLibfuncLongId,
39}
40
41struct ConcreteLibfuncHandle(u64);
43
44#[salsa::interned(revisions = usize::MAX)]
46struct SierraGeneratorTypeLongIdWrapper<'db> {
47 id: SierraGeneratorTypeLongId<'db>,
48}
49
50#[derive(Copy, Clone, PartialEq, Eq, Hash)]
52struct ConcreteTypeHandle(u64);
53
54struct FunctionHandle(u64);
56
57fn intern_concrete_lib_func(
58 db: &dyn Database,
59 id: cairo_lang_sierra::program::ConcreteLibfuncLongId,
60) -> cairo_lang_sierra::ids::ConcreteLibfuncId {
61 let interned = ConcreteLibfuncIdLongWrapper::new(db, id);
62 cairo_lang_sierra::ids::ConcreteLibfuncId::from(interned.0.as_bits())
63}
64
65fn lookup_concrete_lib_func(
66 db: &dyn Database,
67 id: ConcreteLibfuncHandle,
68) -> cairo_lang_sierra::program::ConcreteLibfuncLongId {
69 let interned = ConcreteLibfuncIdLongWrapper::from_id(Id::from_bits(id.0));
70 interned.id(db)
71}
72
73fn intern_concrete_type<'db>(
74 db: &'db dyn Database,
75 id: SierraGeneratorTypeLongId<'db>,
76) -> cairo_lang_sierra::ids::ConcreteTypeId {
77 let interned = SierraGeneratorTypeLongIdWrapper::new(db, id);
78 cairo_lang_sierra::ids::ConcreteTypeId::from(interned.0.as_bits())
79}
80
81fn lookup_concrete_type<'db>(
82 db: &'db dyn Database,
83 id: ConcreteTypeHandle,
84) -> SierraGeneratorTypeLongId<'db> {
85 let interned = SierraGeneratorTypeLongIdWrapper::from_id(Id::from_bits(id.0));
86 interned.id(db)
87}
88
89fn intern_sierra_function<'db>(
90 id: lowering::ids::FunctionId<'db>,
91) -> cairo_lang_sierra::ids::FunctionId {
92 cairo_lang_sierra::ids::FunctionId::from(id.as_intern_id().as_bits())
93}
94
95fn lookup_sierra_function<'db>(id: FunctionHandle) -> lowering::ids::FunctionId<'db> {
96 lowering::ids::FunctionId::from_id(Id::from_bits(id.0))
97}
98
99pub trait SierraGenGroup: Database {
100 fn intern_concrete_lib_func(
101 &self,
102 id: cairo_lang_sierra::program::ConcreteLibfuncLongId,
103 ) -> cairo_lang_sierra::ids::ConcreteLibfuncId {
104 intern_concrete_lib_func(self.as_dyn_database(), id)
105 }
106
107 fn lookup_concrete_lib_func(
108 &self,
109 id: &cairo_lang_sierra::ids::ConcreteLibfuncId,
110 ) -> cairo_lang_sierra::program::ConcreteLibfuncLongId {
111 lookup_concrete_lib_func(self.as_dyn_database(), ConcreteLibfuncHandle(id.id))
112 }
113
114 fn intern_concrete_type<'db>(
115 &'db self,
116 id: SierraGeneratorTypeLongId<'db>,
117 ) -> cairo_lang_sierra::ids::ConcreteTypeId {
118 intern_concrete_type(self.as_dyn_database(), id)
119 }
120
121 fn lookup_concrete_type<'db>(
122 &'db self,
123 id: &cairo_lang_sierra::ids::ConcreteTypeId,
124 ) -> SierraGeneratorTypeLongId<'db> {
125 lookup_concrete_type(self.as_dyn_database(), ConcreteTypeHandle(id.id))
126 }
127
128 fn intern_sierra_function<'db>(
132 &'db self,
133 id: lowering::ids::FunctionId<'db>,
134 ) -> cairo_lang_sierra::ids::FunctionId {
135 intern_sierra_function(id)
136 }
137
138 fn lookup_sierra_function<'db>(
139 &'db self,
140 id: &cairo_lang_sierra::ids::FunctionId,
141 ) -> lowering::ids::FunctionId<'db> {
142 lookup_sierra_function(FunctionHandle(id.id))
143 }
144
145 fn get_concrete_type_id<'db>(
147 &'db self,
148 type_id: semantic::TypeId<'db>,
149 ) -> Maybe<&'db cairo_lang_sierra::ids::ConcreteTypeId> {
150 crate::types::get_concrete_type_id(self.as_dyn_database(), type_id).maybe_as_ref()
151 }
152
153 fn get_index_enum_type_id(
155 &self,
156 index_count: usize,
157 ) -> Maybe<&cairo_lang_sierra::ids::ConcreteTypeId> {
158 crate::types::get_index_enum_type_id(self.as_dyn_database(), (), index_count).maybe_as_ref()
159 }
160
161 fn get_concrete_long_type_id<'db>(
163 &'db self,
164 type_id: semantic::TypeId<'db>,
165 ) -> Maybe<&'db Arc<cairo_lang_sierra::program::ConcreteTypeLongId>> {
166 crate::types::get_concrete_long_type_id(self.as_dyn_database(), type_id).maybe_as_ref()
167 }
168
169 fn is_self_referential<'db>(&self, type_id: semantic::TypeId<'db>) -> Maybe<bool> {
171 crate::types::is_self_referential(self.as_dyn_database(), type_id)
172 }
173
174 fn type_dependencies<'db>(
179 &'db self,
180 type_id: semantic::TypeId<'db>,
181 ) -> Maybe<&'db [semantic::TypeId<'db>]> {
182 Ok(crate::types::type_dependencies(self.as_dyn_database(), type_id).maybe_as_ref()?)
183 }
184
185 fn has_in_deps<'db>(
186 &self,
187 type_id: semantic::TypeId<'db>,
188 needle: semantic::TypeId<'db>,
189 ) -> Maybe<bool> {
190 crate::types::has_in_deps(self.as_dyn_database(), type_id, needle)
191 }
192
193 fn get_function_signature(
196 &self,
197 function_id: cairo_lang_sierra::ids::FunctionId,
198 ) -> Maybe<&cairo_lang_sierra::program::FunctionSignature> {
199 get_function_signature(self.as_dyn_database(), (), function_id).maybe_as_ref()
200 }
201
202 fn get_type_info(
204 &self,
205 concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
206 ) -> Maybe<&cairo_lang_sierra::extensions::types::TypeInfo> {
207 get_type_info(self.as_dyn_database(), (), ConcreteTypeHandle(concrete_type_id.id))
208 .maybe_as_ref()
209 }
210
211 fn priv_function_with_body_sierra_data<'db>(
213 &'db self,
214 function_id: ConcreteFunctionWithBodyId<'db>,
215 ) -> Maybe<&'db function_generator::SierraFunctionWithBodyData<'db>> {
216 function_generator::priv_function_with_body_sierra_data(self.as_dyn_database(), function_id)
217 .maybe_as_ref()
218 }
219 fn function_with_body_sierra<'db>(
221 &'db self,
222 function_id: ConcreteFunctionWithBodyId<'db>,
223 ) -> Maybe<&'db pre_sierra::Function<'db>> {
224 self.priv_function_with_body_sierra_data(function_id)?.function.maybe_as_ref()
225 }
226
227 fn priv_get_dummy_function<'db>(
229 &'db self,
230 function_id: ConcreteFunctionWithBodyId<'db>,
231 ) -> Maybe<&'db pre_sierra::Function<'db>> {
232 function_generator::priv_get_dummy_function(self.as_dyn_database(), function_id)
233 .maybe_as_ref()
234 }
235
236 fn get_ap_change<'db>(
239 &self,
240 function_id: ConcreteFunctionWithBodyId<'db>,
241 ) -> Maybe<SierraApChange> {
242 ap_change::get_ap_change(self.as_dyn_database(), function_id)
243 }
244
245 fn priv_libfunc_dependencies(
247 &self,
248 libfunc_id: cairo_lang_sierra::ids::ConcreteLibfuncId,
249 ) -> &[ConcreteTypeId] {
250 program_generator::priv_libfunc_dependencies(self.as_dyn_database(), (), libfunc_id)
251 }
252
253 fn get_sierra_program_for_functions<'db>(
255 &'db self,
256 requested_function_ids: Vec<ConcreteFunctionWithBodyId<'db>>,
257 ) -> Maybe<&'db SierraProgramWithDebug<'db>> {
258 program_generator::get_sierra_program_for_functions(
259 self.as_dyn_database(),
260 (),
261 requested_function_ids,
262 )
263 .maybe_as_ref()
264 }
265
266 fn get_sierra_program<'db>(
268 &'db self,
269 requested_crate_ids: Vec<CrateId<'db>>,
270 ) -> Maybe<&'db SierraProgramWithDebug<'db>> {
271 program_generator::get_sierra_program(self.as_dyn_database(), (), requested_crate_ids)
272 .maybe_as_ref()
273 }
274}
275impl<T: Database + ?Sized> SierraGenGroup for T {}
276
277#[salsa::tracked(returns(ref))]
278fn get_function_signature(
279 db: &dyn Database,
280 _tracked: Tracked,
281 function_id: cairo_lang_sierra::ids::FunctionId,
282) -> Maybe<cairo_lang_sierra::program::FunctionSignature> {
283 let lowered_function_id = db.lookup_sierra_function(&function_id);
289 let signature = lowered_function_id.signature(db)?;
290
291 let implicits = db
292 .function_implicits(lowered_function_id)?
293 .iter()
294 .map(|ty| db.get_concrete_type_id(*ty).cloned())
295 .collect::<Maybe<Vec<ConcreteTypeId>>>()?;
296
297 let mut all_params = implicits.clone();
299 let mut extra_rets = vec![];
300 for param in &signature.params {
301 let concrete_type_id = db.get_concrete_type_id(param.ty())?;
302 all_params.push(concrete_type_id.clone());
303 }
304 for var in &signature.extra_rets {
305 let concrete_type_id = db.get_concrete_type_id(var.ty())?;
306 extra_rets.push(concrete_type_id.clone());
307 }
308
309 let mut ret_types = implicits;
310
311 let may_panic = !flag_unsafe_panic(db) && db.function_may_panic(lowered_function_id)?;
312 if may_panic {
313 let panic_info = PanicSignatureInfo::new(db, &signature);
314 ret_types.push(db.get_concrete_type_id(panic_info.actual_return_ty)?.clone());
315 } else {
316 ret_types.extend(extra_rets);
317 if !signature.return_type.is_unit(db) {
319 ret_types.push(db.get_concrete_type_id(signature.return_type)?.clone());
320 }
321 }
322
323 Ok(cairo_lang_sierra::program::FunctionSignature { param_types: all_params, ret_types })
324}
325
326pub fn init_sierra_gen_group(db: &mut dyn Database) {
329 Database::zalsa_register_downcaster(db);
330}
331
332#[salsa::tracked(returns(ref))]
333fn get_type_info(
334 db: &dyn Database,
335 _tracked: Tracked,
336 id: ConcreteTypeHandle,
337) -> Maybe<cairo_lang_sierra::extensions::types::TypeInfo> {
338 let long_id = match lookup_concrete_type(db, id) {
339 SierraGeneratorTypeLongId::Regular(long_id) => long_id,
340 SierraGeneratorTypeLongId::CycleBreaker(ty) => {
341 let info = cycle_breaker_info(db, ty)?;
342 return Ok(cairo_lang_sierra::extensions::types::TypeInfo {
343 long_id: db.get_concrete_long_type_id(ty)?.as_ref().clone(),
344 storable: true,
345 droppable: info.droppable,
346 duplicatable: info.duplicatable,
347 zero_sized: false,
348 });
349 }
350 SierraGeneratorTypeLongId::Phantom(ty) => {
351 let long_id = db.get_concrete_long_type_id(ty)?.as_ref().clone();
352 return Ok(cairo_lang_sierra::extensions::types::TypeInfo {
353 long_id,
354 storable: false,
355 droppable: false,
356 duplicatable: false,
357 zero_sized: true,
358 });
359 }
360 };
361 let concrete_ty = cairo_lang_sierra::extensions::core::CoreType::specialize_by_id(
362 &SierraSignatureSpecializationContext(db),
363 &long_id.generic_id,
364 &long_id.generic_args,
365 )
366 .unwrap_or_else(|err| {
367 let mut long_id = long_id.as_ref().clone();
368 replace_ids::DebugReplacer { db }.replace_generic_args(&mut long_id.generic_args);
369 panic!("Got failure while specializing type `{long_id}`: {err}")
370 });
371 Ok(concrete_ty.info().clone())
372}
373
374pub fn sierra_concrete_long_id(
376 db: &dyn Database,
377 concrete_type_id: cairo_lang_sierra::ids::ConcreteTypeId,
378) -> Maybe<Arc<cairo_lang_sierra::program::ConcreteTypeLongId>> {
379 match db.lookup_concrete_type(&concrete_type_id) {
380 SierraGeneratorTypeLongId::Regular(long_id) => Ok(long_id),
381 SierraGeneratorTypeLongId::Phantom(type_id)
382 | SierraGeneratorTypeLongId::CycleBreaker(type_id) => {
383 db.get_concrete_long_type_id(type_id).cloned()
384 }
385 }
386}