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),
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).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
302 pub fn outputs_mut(&mut self) -> &mut [VariableId] {
303 match self {
304 Statement::Const(stmt) => std::slice::from_mut(&mut stmt.output),
305 Statement::Call(stmt) => stmt.outputs.as_mut_slice(),
306 Statement::StructConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
307 Statement::StructDestructure(stmt) => stmt.outputs.as_mut_slice(),
308 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
309 Statement::Snapshot(stmt) => stmt.outputs.as_mut_slice(),
310 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.output),
311 }
312 }
313 pub fn location(&self) -> Option<LocationId> {
314 match &self {
316 Statement::Const(_) => None,
317 Statement::Call(stmt) => Some(stmt.location),
318 Statement::StructConstruct(_) => None,
319 Statement::StructDestructure(stmt) => Some(stmt.input.location),
320 Statement::EnumConstruct(stmt) => Some(stmt.input.location),
321 Statement::Snapshot(stmt) => Some(stmt.input.location),
322 Statement::Desnap(stmt) => Some(stmt.input.location),
323 }
324 }
325 pub fn location_mut(&mut self) -> Option<&mut LocationId> {
326 match self {
327 Statement::Const(_) => None,
328 Statement::Call(stmt) => Some(&mut stmt.location),
329 Statement::StructConstruct(_) => None,
330 Statement::StructDestructure(stmt) => Some(&mut stmt.input.location),
331 Statement::EnumConstruct(stmt) => Some(&mut stmt.input.location),
332 Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
333 Statement::Desnap(stmt) => Some(&mut stmt.input.location),
334 }
335 }
336}
337
338#[derive(Clone, Debug, PartialEq, Eq)]
340pub struct StatementConst {
341 pub value: ConstValue,
343 pub output: VariableId,
345}
346
347#[derive(Clone, Debug, PartialEq, Eq)]
349pub struct StatementCall {
350 pub function: FunctionId,
352 pub inputs: Vec<VarUsage>,
354 pub with_coupon: bool,
357 pub outputs: Vec<VariableId>,
359 pub location: LocationId,
361}
362
363#[derive(Clone, Debug, PartialEq, Eq)]
366pub struct StatementEnumConstruct {
367 pub variant: ConcreteVariant,
368 pub input: VarUsage,
370 pub output: VariableId,
372}
373
374#[derive(Clone, Debug, PartialEq, Eq)]
376pub struct StatementStructConstruct {
377 pub inputs: Vec<VarUsage>,
378 pub output: VariableId,
380}
381
382#[derive(Clone, Debug, PartialEq, Eq)]
385pub struct StatementStructDestructure {
386 pub input: VarUsage,
388 pub outputs: Vec<VariableId>,
390}
391
392#[derive(Clone, Debug, PartialEq, Eq)]
394pub struct StatementSnapshot {
395 pub input: VarUsage,
396 pub outputs: [VariableId; 2],
397}
398impl StatementSnapshot {
399 pub fn new(input: VarUsage, output_original: VariableId, output_snapshot: VariableId) -> Self {
400 Self { input, outputs: [output_original, output_snapshot] }
401 }
402 pub fn original(&self) -> VariableId {
403 self.outputs[0]
404 }
405 pub fn snapshot(&self) -> VariableId {
406 self.outputs[1]
407 }
408}
409
410#[derive(Clone, Debug, PartialEq, Eq)]
412pub struct StatementDesnap {
413 pub input: VarUsage,
414 pub output: VariableId,
416}
417
418#[derive(Clone, Debug, PartialEq, Eq)]
420pub struct MatchArm {
421 pub arm_selector: MatchArmSelector,
423
424 pub block_id: BlockId,
426
427 pub var_ids: Vec<VariableId>,
429}
430
431#[derive(Clone, Debug, PartialEq, Eq)]
434pub struct MatchExternInfo {
435 pub function: FunctionId,
438 pub inputs: Vec<VarUsage>,
440 pub arms: Vec<MatchArm>,
443 pub location: LocationId,
445}
446
447#[derive(Clone, Debug, PartialEq, Eq)]
449pub struct MatchEnumInfo {
450 pub concrete_enum_id: ConcreteEnumId,
451 pub input: VarUsage,
453 pub arms: Vec<MatchArm>,
456 pub location: LocationId,
458}
459#[derive(Clone, Debug, PartialEq, Eq)]
462pub struct MatchEnumValue {
463 pub num_of_arms: usize,
464
465 pub input: VarUsage,
467 pub arms: Vec<MatchArm>,
469 pub location: LocationId,
471}
472
473#[derive(Clone, Debug, PartialEq, Eq)]
474pub enum MatchInfo {
475 Enum(MatchEnumInfo),
476 Extern(MatchExternInfo),
477 Value(MatchEnumValue),
478}
479impl MatchInfo {
480 pub fn inputs(&self) -> &[VarUsage] {
481 match self {
482 MatchInfo::Enum(s) => std::slice::from_ref(&s.input),
483 MatchInfo::Extern(s) => s.inputs.as_slice(),
484 MatchInfo::Value(s) => std::slice::from_ref(&s.input),
485 }
486 }
487
488 pub fn inputs_mut(&mut self) -> &mut [VarUsage] {
489 match self {
490 MatchInfo::Enum(s) => std::slice::from_mut(&mut s.input),
491 MatchInfo::Extern(s) => s.inputs.as_mut_slice(),
492 MatchInfo::Value(s) => std::slice::from_mut(&mut s.input),
493 }
494 }
495 pub fn arms(&self) -> &[MatchArm] {
496 match self {
497 MatchInfo::Enum(s) => &s.arms,
498 MatchInfo::Extern(s) => &s.arms,
499 MatchInfo::Value(s) => &s.arms,
500 }
501 }
502 pub fn arms_mut(&mut self) -> &mut [MatchArm] {
503 match self {
504 MatchInfo::Enum(s) => &mut s.arms,
505 MatchInfo::Extern(s) => &mut s.arms,
506 MatchInfo::Value(s) => &mut s.arms,
507 }
508 }
509 pub fn location(&self) -> &LocationId {
510 match self {
511 MatchInfo::Enum(s) => &s.location,
512 MatchInfo::Extern(s) => &s.location,
513 MatchInfo::Value(s) => &s.location,
514 }
515 }
516 pub fn location_mut(&mut self) -> &mut LocationId {
517 match self {
518 MatchInfo::Enum(s) => &mut s.location,
519 MatchInfo::Extern(s) => &mut s.location,
520 MatchInfo::Value(s) => &mut s.location,
521 }
522 }
523}
524
525#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
527pub enum DependencyType {
528 Call,
530 Cost,
532}