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::items::imp::ImplLookupContext;
14use cairo_lang_semantic::types::TypeInfo;
15use cairo_lang_semantic::{ConcreteEnumId, ConcreteVariant};
16use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
17use cairo_lang_utils::{Intern, LookupIntern};
18use id_arena::{Arena, Id};
19
20pub mod blocks;
21pub use blocks::BlockId;
22use semantic::MatchArmSelector;
23use semantic::expr::inference::InferenceError;
24use semantic::items::constant::ConstValue;
25use semantic::items::imp::ImplId;
26
27use self::blocks::FlatBlocks;
28use crate::db::LoweringGroup;
29use crate::diagnostic::LoweringDiagnostic;
30use crate::ids::{FunctionId, LocationId, Signature};
31
32#[derive(Clone, Debug, Eq, Hash, PartialEq)]
35pub struct Location {
36 pub stable_location: StableLocation,
38 pub notes: Vec<DiagnosticNote>,
42 pub inline_locations: Vec<StableLocation>,
44}
45impl Location {
46 pub fn new(stable_location: StableLocation) -> Self {
47 Self { stable_location, notes: vec![], inline_locations: vec![] }
48 }
49
50 pub fn with_note(mut self, note: DiagnosticNote) -> Self {
52 self.notes.push(note);
53 self
54 }
55
56 pub fn maybe_with_note(mut self, note: Option<DiagnosticNote>) -> Self {
58 let Some(note) = note else {
59 return self;
60 };
61 self.notes.push(note);
62 self
63 }
64
65 pub fn add_note_with_location(
67 self,
68 db: &dyn LoweringGroup,
69 text: &str,
70 location: LocationId,
71 ) -> Self {
72 self.with_note(DiagnosticNote::with_location(
73 text.into(),
74 location.lookup_intern(db).stable_location.diagnostic_location(db.upcast()),
75 ))
76 }
77}
78
79impl DebugWithDb<dyn LoweringGroup> for Location {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn LoweringGroup) -> std::fmt::Result {
81 let files_db = db.upcast();
82 self.stable_location.diagnostic_location(db.upcast()).fmt(f, files_db)?;
83
84 for note in &self.notes {
85 f.write_str("\nnote: ")?;
86 note.fmt(f, files_db)?;
87 }
88 Ok(())
89 }
90}
91
92impl LocationId {
93 pub fn inlined(self, db: &dyn LoweringGroup, inlining_location: StableLocation) -> Self {
95 let mut location = self.lookup_intern(db);
96 location.inline_locations.push(inlining_location);
97 location.intern(db)
98 }
99 pub fn all_locations(self, db: &dyn LoweringGroup) -> Vec<StableLocation> {
101 let location = self.lookup_intern(db);
102 let mut all_locations = vec![location.stable_location];
103 all_locations.extend(location.inline_locations.iter().cloned());
104 all_locations
105 }
106}
107
108pub type VariableId = Id<Variable>;
109
110#[derive(Copy, Clone, Debug, Eq, PartialEq)]
130pub struct VarUsage {
131 pub var_id: VariableId,
132 pub location: LocationId,
133}
134
135#[derive(Clone, Debug, PartialEq, Eq)]
137pub struct FlatLowered {
138 pub diagnostics: Diagnostics<LoweringDiagnostic>,
140 pub signature: Signature,
142 pub variables: Arena<Variable>,
144 pub blocks: FlatBlocks,
146 pub parameters: Vec<VariableId>,
148}
149
150#[derive(Clone, Debug, Default, PartialEq, Eq)]
152pub struct VarRemapping {
153 pub remapping: OrderedHashMap<VariableId, VarUsage>,
155}
156impl Deref for VarRemapping {
157 type Target = OrderedHashMap<VariableId, VarUsage>;
158
159 fn deref(&self) -> &Self::Target {
160 &self.remapping
161 }
162}
163impl DerefMut for VarRemapping {
164 fn deref_mut(&mut self) -> &mut Self::Target {
165 &mut self.remapping
166 }
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
172pub struct FlatBlock {
173 pub statements: Vec<Statement>,
178 pub end: FlatBlockEnd,
180}
181impl Default for FlatBlock {
182 fn default() -> Self {
183 Self { statements: Default::default(), end: FlatBlockEnd::NotSet }
184 }
185}
186impl FlatBlock {
187 pub fn is_set(&self) -> bool {
188 !matches!(self.end, FlatBlockEnd::NotSet)
189 }
190}
191
192#[derive(Clone, Debug, PartialEq, Eq)]
194pub enum FlatBlockEnd {
195 NotSet,
198 Return(Vec<VarUsage>, LocationId),
200 Panic(VarUsage),
202 Goto(BlockId, VarRemapping),
204 Match {
205 info: MatchInfo,
206 },
207}
208
209#[derive(Clone, Debug, PartialEq, Eq)]
211pub struct Variable {
212 pub droppable: Result<ImplId, InferenceError>,
214 pub copyable: Result<ImplId, InferenceError>,
216 pub destruct_impl: Result<ImplId, InferenceError>,
218 pub panic_destruct_impl: Result<ImplId, InferenceError>,
220 pub ty: semantic::TypeId,
222 pub location: LocationId,
224}
225impl Variable {
226 pub fn new(
227 db: &dyn LoweringGroup,
228 ctx: ImplLookupContext,
229 ty: semantic::TypeId,
230 location: LocationId,
231 ) -> Self {
232 let TypeInfo { droppable, copyable, destruct_impl, panic_destruct_impl } =
233 match db.type_info(ctx, ty) {
234 Ok(info) => info,
235 Err(diag_added) => TypeInfo {
236 droppable: Err(InferenceError::Reported(diag_added)),
237 copyable: Err(InferenceError::Reported(diag_added)),
238 destruct_impl: Err(InferenceError::Reported(diag_added)),
239 panic_destruct_impl: Err(InferenceError::Reported(diag_added)),
240 },
241 };
242 Self { copyable, droppable, destruct_impl, panic_destruct_impl, ty, location }
243 }
244}
245
246#[derive(Clone, Debug, PartialEq, Eq)]
248pub enum Statement {
249 Const(StatementConst),
251
252 Call(StatementCall),
254
255 StructConstruct(StatementStructConstruct),
257 StructDestructure(StatementStructDestructure),
258
259 EnumConstruct(StatementEnumConstruct),
261
262 Snapshot(StatementSnapshot),
263 Desnap(StatementDesnap),
264}
265impl Statement {
266 pub fn inputs(&self) -> &[VarUsage] {
267 match &self {
268 Statement::Const(_stmt) => &[],
269 Statement::Call(stmt) => stmt.inputs.as_slice(),
270 Statement::StructConstruct(stmt) => stmt.inputs.as_slice(),
271 Statement::StructDestructure(stmt) => std::slice::from_ref(&stmt.input),
272 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.input),
273 Statement::Snapshot(stmt) => std::slice::from_ref(&stmt.input),
274 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.input),
275 }
276 }
277
278 pub fn inputs_mut(&mut self) -> &mut [VarUsage] {
279 match self {
280 Statement::Const(_stmt) => &mut [],
281 Statement::Call(stmt) => stmt.inputs.as_mut_slice(),
282 Statement::StructConstruct(stmt) => stmt.inputs.as_mut_slice(),
283 Statement::StructDestructure(stmt) => std::slice::from_mut(&mut stmt.input),
284 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.input),
285 Statement::Snapshot(stmt) => std::slice::from_mut(&mut stmt.input),
286 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.input),
287 }
288 }
289
290 pub fn outputs(&self) -> &[VariableId] {
291 match &self {
292 Statement::Const(stmt) => std::slice::from_ref(&stmt.output),
293 Statement::Call(stmt) => stmt.outputs.as_slice(),
294 Statement::StructConstruct(stmt) => std::slice::from_ref(&stmt.output),
295 Statement::StructDestructure(stmt) => stmt.outputs.as_slice(),
296 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.output),
297 Statement::Snapshot(stmt) => stmt.outputs.as_slice(),
298 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.output),
299 }
300 }
301 pub fn location(&self) -> Option<LocationId> {
302 match &self {
304 Statement::Const(_) => None,
305 Statement::Call(stmt) => Some(stmt.location),
306 Statement::StructConstruct(_) => None,
307 Statement::StructDestructure(stmt) => Some(stmt.input.location),
308 Statement::EnumConstruct(stmt) => Some(stmt.input.location),
309 Statement::Snapshot(stmt) => Some(stmt.input.location),
310 Statement::Desnap(stmt) => Some(stmt.input.location),
311 }
312 }
313 pub fn location_mut(&mut self) -> Option<&mut LocationId> {
314 match self {
315 Statement::Const(_) => None,
316 Statement::Call(stmt) => Some(&mut stmt.location),
317 Statement::StructConstruct(_) => None,
318 Statement::StructDestructure(stmt) => Some(&mut stmt.input.location),
319 Statement::EnumConstruct(stmt) => Some(&mut stmt.input.location),
320 Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
321 Statement::Desnap(stmt) => Some(&mut stmt.input.location),
322 }
323 }
324}
325
326#[derive(Clone, Debug, PartialEq, Eq)]
328pub struct StatementConst {
329 pub value: ConstValue,
331 pub output: VariableId,
333}
334
335#[derive(Clone, Debug, PartialEq, Eq)]
337pub struct StatementCall {
338 pub function: FunctionId,
340 pub inputs: Vec<VarUsage>,
342 pub with_coupon: bool,
345 pub outputs: Vec<VariableId>,
347 pub location: LocationId,
349}
350
351#[derive(Clone, Debug, PartialEq, Eq)]
354pub struct StatementEnumConstruct {
355 pub variant: ConcreteVariant,
356 pub input: VarUsage,
358 pub output: VariableId,
360}
361
362#[derive(Clone, Debug, PartialEq, Eq)]
364pub struct StatementStructConstruct {
365 pub inputs: Vec<VarUsage>,
366 pub output: VariableId,
368}
369
370#[derive(Clone, Debug, PartialEq, Eq)]
373pub struct StatementStructDestructure {
374 pub input: VarUsage,
376 pub outputs: Vec<VariableId>,
378}
379
380#[derive(Clone, Debug, PartialEq, Eq)]
382pub struct StatementSnapshot {
383 pub input: VarUsage,
384 outputs: [VariableId; 2],
385}
386impl StatementSnapshot {
387 pub fn new(input: VarUsage, output_original: VariableId, output_snapshot: VariableId) -> Self {
388 Self { input, outputs: [output_original, output_snapshot] }
389 }
390 pub fn original(&self) -> VariableId {
391 self.outputs[0]
392 }
393 pub fn snapshot(&self) -> VariableId {
394 self.outputs[1]
395 }
396}
397
398#[derive(Clone, Debug, PartialEq, Eq)]
400pub struct StatementDesnap {
401 pub input: VarUsage,
402 pub output: VariableId,
404}
405
406#[derive(Clone, Debug, PartialEq, Eq)]
408pub struct MatchArm {
409 pub arm_selector: MatchArmSelector,
411
412 pub block_id: BlockId,
414
415 pub var_ids: Vec<VariableId>,
417}
418
419#[derive(Clone, Debug, PartialEq, Eq)]
422pub struct MatchExternInfo {
423 pub function: FunctionId,
426 pub inputs: Vec<VarUsage>,
428 pub arms: Vec<MatchArm>,
431 pub location: LocationId,
433}
434
435#[derive(Clone, Debug, PartialEq, Eq)]
437pub struct MatchEnumInfo {
438 pub concrete_enum_id: ConcreteEnumId,
439 pub input: VarUsage,
441 pub arms: Vec<MatchArm>,
444 pub location: LocationId,
446}
447#[derive(Clone, Debug, PartialEq, Eq)]
450pub struct MatchEnumValue {
451 pub num_of_arms: usize,
452
453 pub input: VarUsage,
455 pub arms: Vec<MatchArm>,
457 pub location: LocationId,
459}
460
461#[derive(Clone, Debug, PartialEq, Eq)]
462pub enum MatchInfo {
463 Enum(MatchEnumInfo),
464 Extern(MatchExternInfo),
465 Value(MatchEnumValue),
466}
467impl MatchInfo {
468 pub fn inputs(&self) -> &[VarUsage] {
469 match self {
470 MatchInfo::Enum(s) => std::slice::from_ref(&s.input),
471 MatchInfo::Extern(s) => s.inputs.as_slice(),
472 MatchInfo::Value(s) => std::slice::from_ref(&s.input),
473 }
474 }
475
476 pub fn inputs_mut(&mut self) -> &mut [VarUsage] {
477 match self {
478 MatchInfo::Enum(s) => std::slice::from_mut(&mut s.input),
479 MatchInfo::Extern(s) => s.inputs.as_mut_slice(),
480 MatchInfo::Value(s) => std::slice::from_mut(&mut s.input),
481 }
482 }
483 pub fn arms(&self) -> &[MatchArm] {
484 match self {
485 MatchInfo::Enum(s) => &s.arms,
486 MatchInfo::Extern(s) => &s.arms,
487 MatchInfo::Value(s) => &s.arms,
488 }
489 }
490 pub fn location(&self) -> &LocationId {
491 match self {
492 MatchInfo::Enum(s) => &s.location,
493 MatchInfo::Extern(s) => &s.location,
494 MatchInfo::Value(s) => &s.location,
495 }
496 }
497 pub fn location_mut(&mut self) -> &mut LocationId {
498 match self {
499 MatchInfo::Enum(s) => &mut s.location,
500 MatchInfo::Extern(s) => &mut s.location,
501 MatchInfo::Value(s) => &mut s.location,
502 }
503 }
504}
505
506#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
508pub enum DependencyType {
509 Call,
511 Cost,
513}