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::constant::ConstValueId;
17use cairo_lang_semantic::items::imp::ImplLookupContextId;
18use cairo_lang_semantic::types::{TypeInfo, TypesSemantic};
19use cairo_lang_semantic::{ConcreteEnumId, ConcreteVariant};
20use cairo_lang_utils::Intern;
21use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
22use id_arena::{Arena, DefaultArenaBehavior, Id};
23
24pub mod blocks;
25pub use blocks::BlockId;
26use salsa::Database;
27use semantic::MatchArmSelector;
28
29use self::blocks::Blocks;
30use crate::diagnostic::LoweringDiagnostic;
31use crate::fmt::LoweredFormatter;
32use crate::ids::{FunctionId, LocationId, Signature};
33
34#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::Update)]
37pub struct Location<'db> {
38 pub stable_location: StableLocation<'db>,
40 pub notes: Vec<DiagnosticNote<'db>>,
44 pub inline_locations: Vec<StableLocation<'db>>,
46}
47impl<'db> Location<'db> {
48 pub fn new(stable_location: StableLocation<'db>) -> Self {
49 Self { stable_location, notes: vec![], inline_locations: vec![] }
50 }
51
52 pub fn with_note(mut self, note: DiagnosticNote<'db>) -> Self {
54 self.notes.push(note);
55 self
56 }
57
58 pub fn maybe_with_note(mut self, note: Option<DiagnosticNote<'db>>) -> Self {
60 let Some(note) = note else {
61 return self;
62 };
63 self.notes.push(note);
64 self
65 }
66
67 pub fn add_note_with_location(
69 self,
70 db: &'db dyn Database,
71 text: &str,
72 location: LocationId<'db>,
73 ) -> Self {
74 self.with_note(DiagnosticNote::with_location(
75 text.into(),
76 location.long(db).stable_location.span_in_file(db),
77 ))
78 }
79}
80
81impl<'db> DebugWithDb<'db> for Location<'db> {
82 type Db = dyn Database;
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
84 self.stable_location.span_in_file(db).fmt(f, db)?;
85
86 for note in &self.notes {
87 f.write_str("\nnote: ")?;
88 note.fmt(f, db)?;
89 }
90 Ok(())
91 }
92}
93
94impl<'db> LocationId<'db> {
95 pub fn inlined(self, db: &'db dyn Database, inlining_location: StableLocation<'db>) -> Self {
97 let mut location = self.long(db).clone();
98 location.inline_locations.push(inlining_location);
99 location.intern(db)
100 }
101 pub fn all_locations(self, db: &'db dyn Database) -> Vec<StableLocation<'db>> {
103 let location = self.long(db);
104 let mut all_locations = vec![location.stable_location];
105 all_locations.extend(location.inline_locations.iter().cloned());
106 all_locations
107 }
108}
109
110#[derive(Clone, Debug, PartialEq, Eq)]
111pub struct VariableMarker;
112pub type VariableId = Id<VariableMarker>;
113pub type VariableArena<'db> = Arena<Variable<'db>, DefaultArenaBehavior<VariableMarker>>;
114
115#[derive(Copy, Clone, Debug, Eq, PartialEq)]
135pub struct VarUsage<'db> {
136 pub var_id: VariableId,
137 pub location: LocationId<'db>,
138}
139
140#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct Lowered<'db> {
143 pub diagnostics: Diagnostics<'db, LoweringDiagnostic<'db>>,
145 pub signature: Signature<'db>,
147 pub variables: VariableArena<'db>,
149 pub blocks: Blocks<'db>,
151 pub parameters: Vec<VariableId>,
153}
154
155unsafe impl<'db> salsa::Update for Lowered<'db> {
156 unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
157 let old_value = unsafe { &mut *old_pointer };
158 let res = unsafe {
159 Diagnostics::maybe_update(&mut old_value.diagnostics, new_value.diagnostics)
160 | Signature::maybe_update(&mut old_value.signature, new_value.signature)
161 } | (old_value.blocks != new_value.blocks);
162 if res {
163 old_value.variables = new_value.variables;
164 old_value.parameters = new_value.parameters;
165 old_value.blocks = new_value.blocks;
166 }
167 res
168 }
169}
170
171#[derive(Clone, Debug, Default, PartialEq, Eq)]
173pub struct VarRemapping<'db> {
174 pub remapping: OrderedHashMap<VariableId, VarUsage<'db>>,
176}
177impl<'db> Deref for VarRemapping<'db> {
178 type Target = OrderedHashMap<VariableId, VarUsage<'db>>;
179
180 fn deref(&self) -> &Self::Target {
181 &self.remapping
182 }
183}
184impl<'db> DerefMut for VarRemapping<'db> {
185 fn deref_mut(&mut self) -> &mut Self::Target {
186 &mut self.remapping
187 }
188}
189
190#[derive(Clone, Debug, PartialEq, Eq)]
192pub struct Block<'db> {
193 pub statements: Vec<Statement<'db>>,
195 pub end: BlockEnd<'db>,
197}
198impl<'db> Default for Block<'db> {
199 fn default() -> Self {
200 Self { statements: Default::default(), end: BlockEnd::NotSet }
201 }
202}
203impl<'db> Block<'db> {
204 pub fn is_set(&self) -> bool {
205 !matches!(self.end, BlockEnd::NotSet)
206 }
207}
208
209#[derive(Clone, Debug, PartialEq, Eq)]
211pub enum BlockEnd<'db> {
212 NotSet,
215 Return(Vec<VarUsage<'db>>, LocationId<'db>),
217 Panic(VarUsage<'db>),
219 Goto(BlockId, VarRemapping<'db>),
221 Match {
222 info: MatchInfo<'db>,
223 },
224}
225
226#[derive(Clone, Debug, PartialEq, Eq)]
228pub struct Variable<'db> {
229 pub ty: semantic::TypeId<'db>,
231 pub location: LocationId<'db>,
233 pub info: TypeInfo<'db>,
235}
236
237impl<'db> DebugWithDb<'db> for Variable<'db> {
238 type Db = LoweredFormatter<'db>;
239
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _ctx: &Self::Db) -> std::fmt::Result {
241 write!(f, "Variable({:?})", self.ty)
242 }
243}
244
245impl<'db> Variable<'db> {
246 pub fn new(
247 db: &'db dyn Database,
248 ctx: ImplLookupContextId<'db>,
249 ty: semantic::TypeId<'db>,
250 location: LocationId<'db>,
251 ) -> Self {
252 Self { ty, location, info: db.type_info(ctx, ty) }
253 }
254
255 pub fn with_default_context(
257 db: &'db dyn Database,
258 ty: semantic::TypeId<'db>,
259 location: LocationId<'db>,
260 ) -> Self {
261 Self {
262 ty,
263 location,
264 info: TypeInfo {
265 copyable: db.copyable(ty),
266 droppable: db.droppable(ty),
267 destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
268 concrete_destruct_trait(db, ty),
269 ))),
270 panic_destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
271 concrete_panic_destruct_trait(db, ty),
272 ))),
273 },
274 }
275 }
276}
277
278#[derive(Clone, Debug, PartialEq, Eq)]
280pub enum Statement<'db> {
281 Const(StatementConst<'db>),
283
284 Call(StatementCall<'db>),
286
287 StructConstruct(StatementStructConstruct<'db>),
289 StructDestructure(StatementStructDestructure<'db>),
290
291 EnumConstruct(StatementEnumConstruct<'db>),
293
294 Snapshot(StatementSnapshot<'db>),
295 Desnap(StatementDesnap<'db>),
296}
297impl<'db> Statement<'db> {
298 pub fn inputs(&self) -> &[VarUsage<'db>] {
299 match &self {
300 Statement::Const(_stmt) => &[],
301 Statement::Call(stmt) => stmt.inputs.as_slice(),
302 Statement::StructConstruct(stmt) => stmt.inputs.as_slice(),
303 Statement::StructDestructure(stmt) => std::slice::from_ref(&stmt.input),
304 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.input),
305 Statement::Snapshot(stmt) => std::slice::from_ref(&stmt.input),
306 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.input),
307 }
308 }
309
310 pub fn inputs_mut(&mut self) -> &mut [VarUsage<'db>] {
311 match self {
312 Statement::Const(_stmt) => &mut [],
313 Statement::Call(stmt) => stmt.inputs.as_mut_slice(),
314 Statement::StructConstruct(stmt) => stmt.inputs.as_mut_slice(),
315 Statement::StructDestructure(stmt) => std::slice::from_mut(&mut stmt.input),
316 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.input),
317 Statement::Snapshot(stmt) => std::slice::from_mut(&mut stmt.input),
318 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.input),
319 }
320 }
321
322 pub fn outputs(&self) -> &[VariableId] {
323 match self {
324 Statement::Const(stmt) => std::slice::from_ref(&stmt.output),
325 Statement::Call(stmt) => stmt.outputs.as_slice(),
326 Statement::StructConstruct(stmt) => std::slice::from_ref(&stmt.output),
327 Statement::StructDestructure(stmt) => stmt.outputs.as_slice(),
328 Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.output),
329 Statement::Snapshot(stmt) => stmt.outputs.as_slice(),
330 Statement::Desnap(stmt) => std::slice::from_ref(&stmt.output),
331 }
332 }
333
334 pub fn outputs_mut(&mut self) -> &mut [VariableId] {
335 match self {
336 Statement::Const(stmt) => std::slice::from_mut(&mut stmt.output),
337 Statement::Call(stmt) => stmt.outputs.as_mut_slice(),
338 Statement::StructConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
339 Statement::StructDestructure(stmt) => stmt.outputs.as_mut_slice(),
340 Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
341 Statement::Snapshot(stmt) => stmt.outputs.as_mut_slice(),
342 Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.output),
343 }
344 }
345 pub fn location(&self) -> Option<LocationId<'db>> {
346 match &self {
348 Statement::Const(_) => None,
349 Statement::Call(stmt) => Some(stmt.location),
350 Statement::StructConstruct(_) => None,
351 Statement::StructDestructure(stmt) => Some(stmt.input.location),
352 Statement::EnumConstruct(stmt) => Some(stmt.input.location),
353 Statement::Snapshot(stmt) => Some(stmt.input.location),
354 Statement::Desnap(stmt) => Some(stmt.input.location),
355 }
356 }
357 pub fn location_mut(&mut self) -> Option<&mut LocationId<'db>> {
358 match self {
359 Statement::Const(_) => None,
360 Statement::Call(stmt) => Some(&mut stmt.location),
361 Statement::StructConstruct(_) => None,
362 Statement::StructDestructure(stmt) => Some(&mut stmt.input.location),
363 Statement::EnumConstruct(stmt) => Some(&mut stmt.input.location),
364 Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
365 Statement::Desnap(stmt) => Some(&mut stmt.input.location),
366 }
367 }
368}
369
370#[derive(Clone, Debug, PartialEq, Eq)]
372pub struct StatementConst<'db> {
373 pub value: ConstValueId<'db>,
375 pub output: VariableId,
377 pub boxed: bool,
379}
380impl<'db> StatementConst<'db> {
381 pub fn new(value: ConstValueId<'db>, output: VariableId, boxed: bool) -> Self {
383 Self { value, output, boxed }
384 }
385 pub fn new_flat(value: ConstValueId<'db>, output: VariableId) -> Self {
387 Self::new(value, output, false)
388 }
389 pub fn new_boxed(value: ConstValueId<'db>, output: VariableId) -> Self {
391 Self::new(value, output, true)
392 }
393}
394
395#[derive(Clone, Debug, PartialEq, Eq)]
397pub struct StatementCall<'db> {
398 pub function: FunctionId<'db>,
400 pub inputs: Vec<VarUsage<'db>>,
402 pub with_coupon: bool,
405 pub outputs: Vec<VariableId>,
407 pub location: LocationId<'db>,
409}
410
411#[derive(Clone, Debug, PartialEq, Eq)]
414pub struct StatementEnumConstruct<'db> {
415 pub variant: ConcreteVariant<'db>,
416 pub input: VarUsage<'db>,
418 pub output: VariableId,
420}
421
422#[derive(Clone, Debug, PartialEq, Eq)]
424pub struct StatementStructConstruct<'db> {
425 pub inputs: Vec<VarUsage<'db>>,
426 pub output: VariableId,
428}
429
430#[derive(Clone, Debug, PartialEq, Eq)]
433pub struct StatementStructDestructure<'db> {
434 pub input: VarUsage<'db>,
436 pub outputs: Vec<VariableId>,
438}
439
440#[derive(Clone, Debug, PartialEq, Eq)]
442pub struct StatementSnapshot<'db> {
443 pub input: VarUsage<'db>,
444 pub outputs: [VariableId; 2],
445}
446impl<'db> StatementSnapshot<'db> {
447 pub fn new(
448 input: VarUsage<'db>,
449 output_original: VariableId,
450 output_snapshot: VariableId,
451 ) -> Self {
452 Self { input, outputs: [output_original, output_snapshot] }
453 }
454 pub fn original(&self) -> VariableId {
455 self.outputs[0]
456 }
457 pub fn snapshot(&self) -> VariableId {
458 self.outputs[1]
459 }
460}
461
462#[derive(Clone, Debug, PartialEq, Eq)]
464pub struct StatementDesnap<'db> {
465 pub input: VarUsage<'db>,
466 pub output: VariableId,
468}
469
470#[derive(Clone, Debug, PartialEq, Eq)]
472pub struct MatchArm<'db> {
473 pub arm_selector: MatchArmSelector<'db>,
475
476 pub block_id: BlockId,
478
479 pub var_ids: Vec<VariableId>,
481}
482
483#[derive(Clone, Debug, PartialEq, Eq)]
486pub struct MatchExternInfo<'db> {
487 pub function: FunctionId<'db>,
490 pub inputs: Vec<VarUsage<'db>>,
492 pub arms: Vec<MatchArm<'db>>,
495 pub location: LocationId<'db>,
497}
498
499#[derive(Clone, Debug, PartialEq, Eq)]
501pub struct MatchEnumInfo<'db> {
502 pub concrete_enum_id: ConcreteEnumId<'db>,
503 pub input: VarUsage<'db>,
505 pub arms: Vec<MatchArm<'db>>,
508 pub location: LocationId<'db>,
510}
511#[derive(Clone, Debug, PartialEq, Eq)]
514pub struct MatchEnumValue<'db> {
515 pub num_of_arms: usize,
516
517 pub input: VarUsage<'db>,
519 pub arms: Vec<MatchArm<'db>>,
521 pub location: LocationId<'db>,
523}
524
525#[derive(Clone, Debug, PartialEq, Eq)]
526pub enum MatchInfo<'db> {
527 Enum(MatchEnumInfo<'db>),
528 Extern(MatchExternInfo<'db>),
529 Value(MatchEnumValue<'db>),
530}
531impl<'db> MatchInfo<'db> {
532 pub fn inputs(&self) -> &[VarUsage<'db>] {
533 match self {
534 MatchInfo::Enum(s) => std::slice::from_ref(&s.input),
535 MatchInfo::Extern(s) => s.inputs.as_slice(),
536 MatchInfo::Value(s) => std::slice::from_ref(&s.input),
537 }
538 }
539
540 pub fn inputs_mut(&mut self) -> &mut [VarUsage<'db>] {
541 match self {
542 MatchInfo::Enum(s) => std::slice::from_mut(&mut s.input),
543 MatchInfo::Extern(s) => s.inputs.as_mut_slice(),
544 MatchInfo::Value(s) => std::slice::from_mut(&mut s.input),
545 }
546 }
547 pub fn arms(&self) -> &[MatchArm<'db>] {
548 match self {
549 MatchInfo::Enum(s) => &s.arms,
550 MatchInfo::Extern(s) => &s.arms,
551 MatchInfo::Value(s) => &s.arms,
552 }
553 }
554 pub fn arms_mut(&mut self) -> &mut [MatchArm<'db>] {
555 match self {
556 MatchInfo::Enum(s) => &mut s.arms,
557 MatchInfo::Extern(s) => &mut s.arms,
558 MatchInfo::Value(s) => &mut s.arms,
559 }
560 }
561 pub fn location(&self) -> &LocationId<'db> {
562 match self {
563 MatchInfo::Enum(s) => &s.location,
564 MatchInfo::Extern(s) => &s.location,
565 MatchInfo::Value(s) => &s.location,
566 }
567 }
568 pub fn location_mut(&mut self) -> &mut LocationId<'db> {
569 match self {
570 MatchInfo::Enum(s) => &mut s.location,
571 MatchInfo::Extern(s) => &mut s.location,
572 MatchInfo::Value(s) => &mut s.location,
573 }
574 }
575}
576
577#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
579pub enum DependencyType {
580 Call,
582 Cost,
584}
585
586#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
588pub enum LoweringStage {
589 Monomorphized,
591 PreOptimizations,
598 PostBaseline,
601 Final,
604}