1use std::ops::{Deref, DerefMut};
8
9use cairo_lang_debug::DebugWithDb;
10use cairo_lang_defs::diagnostic_utils::StableLocation;
11use cairo_lang_diagnostics::{DiagnosticNote, Diagnostics};
12use cairo_lang_semantic as semantic;
13use cairo_lang_semantic::corelib::{concrete_destruct_trait, concrete_panic_destruct_trait};
14use cairo_lang_semantic::expr::inference::InferenceError;
15use cairo_lang_semantic::expr::inference::solver::Ambiguity;
16use cairo_lang_semantic::items::imp::ImplLookupContext;
17use cairo_lang_semantic::types::TypeInfo;
18use cairo_lang_semantic::{ConcreteEnumId, ConcreteVariant};
19use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
20use cairo_lang_utils::{Intern, LookupIntern};
21use id_arena::{Arena, Id};
22
23pub mod blocks;
24pub use blocks::BlockId;
25use semantic::MatchArmSelector;
26use semantic::items::constant::ConstValue;
27
28use self::blocks::Blocks;
29use crate::db::LoweringGroup;
30use crate::diagnostic::LoweringDiagnostic;
31use crate::ids::{FunctionId, LocationId, Signature};
32
33#[derive(Clone, Debug, Eq, Hash, PartialEq)]
36pub struct Location {
37 pub stable_location: StableLocation,
39 pub notes: Vec<DiagnosticNote>,
43 pub inline_locations: Vec<StableLocation>,
45}
46impl Location {
47 pub fn new(stable_location: StableLocation) -> Self {
48 Self { stable_location, notes: vec![], inline_locations: vec![] }
49 }
50
51 pub fn with_note(mut self, note: DiagnosticNote) -> Self {
53 self.notes.push(note);
54 self
55 }
56
57 pub fn maybe_with_note(mut self, note: Option<DiagnosticNote>) -> Self {
59 let Some(note) = note else {
60 return self;
61 };
62 self.notes.push(note);
63 self
64 }
65
66 pub fn add_note_with_location(
68 self,
69 db: &dyn LoweringGroup,
70 text: &str,
71 location: LocationId,
72 ) -> Self {
73 self.with_note(DiagnosticNote::with_location(
74 text.into(),
75 location.lookup_intern(db).stable_location.diagnostic_location(db),
76 ))
77 }
78}
79
80impl DebugWithDb<dyn LoweringGroup> for Location {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn LoweringGroup) -> std::fmt::Result {
82 let files_db = db.upcast();
83 self.stable_location.diagnostic_location(db).fmt(f, files_db)?;
84
85 for note in &self.notes {
86 f.write_str("\nnote: ")?;
87 note.fmt(f, files_db)?;
88 }
89 Ok(())
90 }
91}
92
93impl LocationId {
94 pub fn inlined(self, db: &dyn LoweringGroup, inlining_location: StableLocation) -> Self {
96 let mut location = self.lookup_intern(db);
97 location.inline_locations.push(inlining_location);
98 location.intern(db)
99 }
100 pub fn all_locations(self, db: &dyn LoweringGroup) -> Vec<StableLocation> {
102 let location = self.lookup_intern(db);
103 let mut all_locations = vec![location.stable_location];
104 all_locations.extend(location.inline_locations.iter().cloned());
105 all_locations
106 }
107}
108
109pub type VariableId = Id<Variable>;
110
111#[derive(Copy, Clone, Debug, Eq, PartialEq)]
131pub struct VarUsage {
132 pub var_id: VariableId,
133 pub location: LocationId,
134}
135
136#[derive(Clone, Debug, PartialEq, Eq)]
138pub struct Lowered {
139 pub diagnostics: Diagnostics<LoweringDiagnostic>,
141 pub signature: Signature,
143 pub variables: Arena<Variable>,
145 pub blocks: Blocks,
147 pub parameters: Vec<VariableId>,
149}
150
151#[derive(Clone, Debug, Default, PartialEq, Eq)]
153pub struct VarRemapping {
154 pub remapping: OrderedHashMap<VariableId, VarUsage>,
156}
157impl Deref for VarRemapping {
158 type Target = OrderedHashMap<VariableId, VarUsage>;
159
160 fn deref(&self) -> &Self::Target {
161 &self.remapping
162 }
163}
164impl DerefMut for VarRemapping {
165 fn deref_mut(&mut self) -> &mut Self::Target {
166 &mut self.remapping
167 }
168}
169
170#[derive(Clone, Debug, PartialEq, Eq)]
172pub struct Block {
173 pub statements: Vec<Statement>,
175 pub end: BlockEnd,
177}
178impl Default for Block {
179 fn default() -> Self {
180 Self { statements: Default::default(), end: BlockEnd::NotSet }
181 }
182}
183impl Block {
184 pub fn is_set(&self) -> bool {
185 !matches!(self.end, BlockEnd::NotSet)
186 }
187}
188
189#[derive(Clone, Debug, PartialEq, Eq)]
191pub enum BlockEnd {
192 NotSet,
195 Return(Vec<VarUsage>, LocationId),
197 Panic(VarUsage),
199 Goto(BlockId, VarRemapping),
201 Match {
202 info: MatchInfo,
203 },
204}
205
206#[derive(Clone, Debug, PartialEq, Eq)]
208pub struct Variable {
209 pub ty: semantic::TypeId,
211 pub location: LocationId,
213 pub info: TypeInfo,
215}
216impl Variable {
217 pub fn new(
218 db: &dyn LoweringGroup,
219 ctx: ImplLookupContext,
220 ty: semantic::TypeId,
221 location: LocationId,
222 ) -> Self {
223 Self { ty, location, info: db.type_info(ctx, ty) }
224 }
225
226 pub fn with_default_context(
228 db: &dyn LoweringGroup,
229 ty: semantic::TypeId,
230 location: LocationId,
231 ) -> Self {
232 Self {
233 ty,
234 location,
235 info: TypeInfo {
236 copyable: db.copyable(ty),
237 droppable: db.droppable(ty),
238 destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
239 concrete_destruct_trait(db, ty),
240 ))),
241 panic_destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
242 concrete_panic_destruct_trait(db, ty),
243 ))),
244 },
245 }
246 }
247}
248
249#[derive(Clone, Debug, PartialEq, Eq)]
251pub enum Statement {
252 Const(StatementConst),
254
255 Call(StatementCall),
257
258 StructConstruct(StatementStructConstruct),
260 StructDestructure(StatementStructDestructure),
261
262 EnumConstruct(StatementEnumConstruct),
264
265 Snapshot(StatementSnapshot),
266 Desnap(StatementDesnap),
267}
268impl Statement {
269 pub fn inputs(&self) -> &[VarUsage] {
270 match &self {
271 Statement::Const(_stmt) => &[],
272 Statement::Call(stmt) => stmt.inputs.as_slice(),
273 Statement::StructConstruct(stmt) => stmt.inputs.as_slice(),
274 Statement::StructDestructure(stmt) => std::slice::from_ref(&stmt.input),
275 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.input),
276 Statement::Snapshot(stmt) => std::slice::from_ref(&stmt.input),
277 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.input),
278 }
279 }
280
281 pub fn inputs_mut(&mut self) -> &mut [VarUsage] {
282 match self {
283 Statement::Const(_stmt) => &mut [],
284 Statement::Call(stmt) => stmt.inputs.as_mut_slice(),
285 Statement::StructConstruct(stmt) => stmt.inputs.as_mut_slice(),
286 Statement::StructDestructure(stmt) => std::slice::from_mut(&mut stmt.input),
287 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.input),
288 Statement::Snapshot(stmt) => std::slice::from_mut(&mut stmt.input),
289 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.input),
290 }
291 }
292
293 pub fn outputs(&self) -> &[VariableId] {
294 match self {
295 Statement::Const(stmt) => std::slice::from_ref(&stmt.output),
296 Statement::Call(stmt) => stmt.outputs.as_slice(),
297 Statement::StructConstruct(stmt) => std::slice::from_ref(&stmt.output),
298 Statement::StructDestructure(stmt) => stmt.outputs.as_slice(),
299 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.output),
300 Statement::Snapshot(stmt) => stmt.outputs.as_slice(),
301 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.output),
302 }
303 }
304
305 pub fn outputs_mut(&mut self) -> &mut [VariableId] {
306 match self {
307 Statement::Const(stmt) => std::slice::from_mut(&mut stmt.output),
308 Statement::Call(stmt) => stmt.outputs.as_mut_slice(),
309 Statement::StructConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
310 Statement::StructDestructure(stmt) => stmt.outputs.as_mut_slice(),
311 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
312 Statement::Snapshot(stmt) => stmt.outputs.as_mut_slice(),
313 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.output),
314 }
315 }
316 pub fn location(&self) -> Option<LocationId> {
317 match &self {
319 Statement::Const(_) => None,
320 Statement::Call(stmt) => Some(stmt.location),
321 Statement::StructConstruct(_) => None,
322 Statement::StructDestructure(stmt) => Some(stmt.input.location),
323 Statement::EnumConstruct(stmt) => Some(stmt.input.location),
324 Statement::Snapshot(stmt) => Some(stmt.input.location),
325 Statement::Desnap(stmt) => Some(stmt.input.location),
326 }
327 }
328 pub fn location_mut(&mut self) -> Option<&mut LocationId> {
329 match self {
330 Statement::Const(_) => None,
331 Statement::Call(stmt) => Some(&mut stmt.location),
332 Statement::StructConstruct(_) => None,
333 Statement::StructDestructure(stmt) => Some(&mut stmt.input.location),
334 Statement::EnumConstruct(stmt) => Some(&mut stmt.input.location),
335 Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
336 Statement::Desnap(stmt) => Some(&mut stmt.input.location),
337 }
338 }
339}
340
341#[derive(Clone, Debug, PartialEq, Eq)]
343pub struct StatementConst {
344 pub value: ConstValue,
346 pub output: VariableId,
348}
349
350#[derive(Clone, Debug, PartialEq, Eq)]
352pub struct StatementCall {
353 pub function: FunctionId,
355 pub inputs: Vec<VarUsage>,
357 pub with_coupon: bool,
360 pub outputs: Vec<VariableId>,
362 pub location: LocationId,
364}
365
366#[derive(Clone, Debug, PartialEq, Eq)]
369pub struct StatementEnumConstruct {
370 pub variant: ConcreteVariant,
371 pub input: VarUsage,
373 pub output: VariableId,
375}
376
377#[derive(Clone, Debug, PartialEq, Eq)]
379pub struct StatementStructConstruct {
380 pub inputs: Vec<VarUsage>,
381 pub output: VariableId,
383}
384
385#[derive(Clone, Debug, PartialEq, Eq)]
388pub struct StatementStructDestructure {
389 pub input: VarUsage,
391 pub outputs: Vec<VariableId>,
393}
394
395#[derive(Clone, Debug, PartialEq, Eq)]
397pub struct StatementSnapshot {
398 pub input: VarUsage,
399 pub outputs: [VariableId; 2],
400}
401impl StatementSnapshot {
402 pub fn new(input: VarUsage, output_original: VariableId, output_snapshot: VariableId) -> Self {
403 Self { input, outputs: [output_original, output_snapshot] }
404 }
405 pub fn original(&self) -> VariableId {
406 self.outputs[0]
407 }
408 pub fn snapshot(&self) -> VariableId {
409 self.outputs[1]
410 }
411}
412
413#[derive(Clone, Debug, PartialEq, Eq)]
415pub struct StatementDesnap {
416 pub input: VarUsage,
417 pub output: VariableId,
419}
420
421#[derive(Clone, Debug, PartialEq, Eq)]
423pub struct MatchArm {
424 pub arm_selector: MatchArmSelector,
426
427 pub block_id: BlockId,
429
430 pub var_ids: Vec<VariableId>,
432}
433
434#[derive(Clone, Debug, PartialEq, Eq)]
437pub struct MatchExternInfo {
438 pub function: FunctionId,
441 pub inputs: Vec<VarUsage>,
443 pub arms: Vec<MatchArm>,
446 pub location: LocationId,
448}
449
450#[derive(Clone, Debug, PartialEq, Eq)]
452pub struct MatchEnumInfo {
453 pub concrete_enum_id: ConcreteEnumId,
454 pub input: VarUsage,
456 pub arms: Vec<MatchArm>,
459 pub location: LocationId,
461}
462#[derive(Clone, Debug, PartialEq, Eq)]
465pub struct MatchEnumValue {
466 pub num_of_arms: usize,
467
468 pub input: VarUsage,
470 pub arms: Vec<MatchArm>,
472 pub location: LocationId,
474}
475
476#[derive(Clone, Debug, PartialEq, Eq)]
477pub enum MatchInfo {
478 Enum(MatchEnumInfo),
479 Extern(MatchExternInfo),
480 Value(MatchEnumValue),
481}
482impl MatchInfo {
483 pub fn inputs(&self) -> &[VarUsage] {
484 match self {
485 MatchInfo::Enum(s) => std::slice::from_ref(&s.input),
486 MatchInfo::Extern(s) => s.inputs.as_slice(),
487 MatchInfo::Value(s) => std::slice::from_ref(&s.input),
488 }
489 }
490
491 pub fn inputs_mut(&mut self) -> &mut [VarUsage] {
492 match self {
493 MatchInfo::Enum(s) => std::slice::from_mut(&mut s.input),
494 MatchInfo::Extern(s) => s.inputs.as_mut_slice(),
495 MatchInfo::Value(s) => std::slice::from_mut(&mut s.input),
496 }
497 }
498 pub fn arms(&self) -> &[MatchArm] {
499 match self {
500 MatchInfo::Enum(s) => &s.arms,
501 MatchInfo::Extern(s) => &s.arms,
502 MatchInfo::Value(s) => &s.arms,
503 }
504 }
505 pub fn arms_mut(&mut self) -> &mut [MatchArm] {
506 match self {
507 MatchInfo::Enum(s) => &mut s.arms,
508 MatchInfo::Extern(s) => &mut s.arms,
509 MatchInfo::Value(s) => &mut s.arms,
510 }
511 }
512 pub fn location(&self) -> &LocationId {
513 match self {
514 MatchInfo::Enum(s) => &s.location,
515 MatchInfo::Extern(s) => &s.location,
516 MatchInfo::Value(s) => &s.location,
517 }
518 }
519 pub fn location_mut(&mut self) -> &mut LocationId {
520 match self {
521 MatchInfo::Enum(s) => &mut s.location,
522 MatchInfo::Extern(s) => &mut s.location,
523 MatchInfo::Value(s) => &mut s.location,
524 }
525 }
526}
527
528#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
530pub enum DependencyType {
531 Call,
533 Cost,
535}
536
537#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
539pub enum LoweringStage {
540 Monomorphized,
542 PreOptimizations,
549 PostBaseline,
552 Final,
555}