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