Skip to main content

cairo_lang_lowering/
objects.rs

1//! Intermediate representation objects after lowering from semantic.
2//!
3//! This representation is SSA (static single-assignment): each variable is defined before usage and
4//! assigned once. It is also normal form: each function argument is a variable, rather than a
5//! compound expression.
6
7use std::ops::{Deref, DerefMut, Index};
8
9use cairo_lang_debug::DebugWithDb;
10use cairo_lang_defs::diagnostic_utils::StableLocation;
11use cairo_lang_diagnostics::{DiagnosticNote, Diagnostics};
12use cairo_lang_proc_macros::HeapSize;
13use cairo_lang_semantic as semantic;
14use cairo_lang_semantic::corelib::{concrete_destruct_trait, concrete_panic_destruct_trait};
15use cairo_lang_semantic::expr::inference::InferenceError;
16use cairo_lang_semantic::expr::inference::solver::Ambiguity;
17use cairo_lang_semantic::items::constant::ConstValueId;
18use cairo_lang_semantic::items::imp::ImplLookupContextId;
19use cairo_lang_semantic::types::{TypeInfo, TypesSemantic};
20use cairo_lang_semantic::{ConcreteEnumId, ConcreteVariant};
21use cairo_lang_utils::Intern;
22use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
23use id_arena::{Arena, DefaultArenaBehavior, Id};
24
25pub mod blocks;
26pub use blocks::BlockId;
27use salsa::Database;
28use semantic::MatchArmSelector;
29
30use self::blocks::Blocks;
31use crate::analysis::StatementLocation;
32use crate::diagnostic::LoweringDiagnostic;
33use crate::fmt::LoweredFormatter;
34use crate::ids::{FunctionId, LocationId, Signature};
35
36/// The Location struct represents the source location of a lowered object. It is used to store the
37/// most relevant source location for a lowering object.
38#[derive(Clone, Debug, Eq, Hash, PartialEq, HeapSize, salsa::SalsaValue)]
39pub struct Location<'db> {
40    /// The stable location of the object.
41    pub stable_location: StableLocation<'db>,
42    /// Additional notes about the origin of the object, for example if the object was
43    /// auto-generated by the compiler.
44    /// New notes are appended to the end of the vector.
45    pub notes: Vec<DiagnosticNote<'db>>,
46    /// Function call locations where this value was inlined from.
47    pub inline_locations: Vec<StableLocation<'db>>,
48}
49impl<'db> Location<'db> {
50    pub fn new(stable_location: StableLocation<'db>) -> Self {
51        Self { stable_location, notes: vec![], inline_locations: vec![] }
52    }
53
54    /// Creates a new Location with the given note as the last note.
55    pub fn with_note(mut self, note: DiagnosticNote<'db>) -> Self {
56        self.notes.push(note);
57        self
58    }
59
60    /// Creates a new Location with the given note as the last note.
61    pub fn maybe_with_note(mut self, note: Option<DiagnosticNote<'db>>) -> Self {
62        let Some(note) = note else {
63            return self;
64        };
65        self.notes.push(note);
66        self
67    }
68
69    /// Creates a new Location with a note from the given text and location.
70    pub fn add_note_with_location(
71        self,
72        db: &'db dyn Database,
73        text: &str,
74        location: LocationId<'db>,
75    ) -> Self {
76        self.with_note(DiagnosticNote::with_location(
77            text.into(),
78            location.long(db).stable_location.span_in_file(db),
79        ))
80    }
81}
82
83impl<'db> DebugWithDb<'db> for Location<'db> {
84    type Db = dyn Database;
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
86        self.stable_location.span_in_file(db).fmt(f, db)?;
87
88        for note in &self.notes {
89            f.write_str("\nnote: ")?;
90            note.fmt(f, db)?;
91        }
92        Ok(())
93    }
94}
95
96impl<'db> LocationId<'db> {
97    /// Returns the location with the added inlining location of it.
98    pub fn inlined(self, db: &'db dyn Database, inlining_location: StableLocation<'db>) -> Self {
99        let mut location = self.long(db).clone();
100        location.inline_locations.push(inlining_location);
101        location.intern(db)
102    }
103    /// Returns all relevant stable pointers of the location.
104    pub fn all_locations(self, db: &'db dyn Database) -> Vec<StableLocation<'db>> {
105        let location = self.long(db);
106        let mut all_locations = vec![location.stable_location];
107        all_locations.extend(location.inline_locations.iter().cloned());
108        all_locations
109    }
110}
111
112#[derive(Clone, Debug, PartialEq, Eq)]
113pub struct VariableMarker;
114pub type VariableId = Id<VariableMarker>;
115pub type VariableArena<'db> = Arena<Variable<'db>, DefaultArenaBehavior<VariableMarker>>;
116
117/// Represents a usage of a variable.
118///
119/// For example if we have:
120///
121/// fn foo(a: u32) {
122///     1 + a
123/// }
124///
125/// Then the right hand side of the tail expression `1 + a` is a VarUsage object with
126/// the variable id of the variable `a` and the location:
127///     1 + a
128///         ^
129/// Note that the location associated with the variable that was assigned to 'a' is
130/// fn foo(a: u32)
131///        ^
132/// and it is different from the location in the VarUsage.
133///
134/// The tail expression `1 + a` is also going to be assigned a variable and a VarUsage.
135/// in that case, the location of both the variable and the usage will be the same.
136#[derive(Copy, Clone, Debug, Eq, PartialEq)]
137pub struct VarUsage<'db> {
138    pub var_id: VariableId,
139    pub location: LocationId<'db>,
140}
141
142/// A lowered function code using flat blocks.
143#[derive(Clone, Debug, PartialEq, Eq, salsa::SalsaValue)]
144pub struct Lowered<'db> {
145    /// Diagnostics produced while lowering.
146    pub diagnostics: Diagnostics<'db, LoweringDiagnostic<'db>>,
147    /// Function signature.
148    pub signature: Signature<'db>,
149    /// Arena of allocated lowered variables.
150    /// SAFETY: `id_arena::Arena` is a foreign type, so this cannot be derived; the arena holds
151    /// owned `Variable` values that are safe to retain across revisions.
152    #[salsa_value(unsafe(prove_safe_to_retain_manually))]
153    pub variables: VariableArena<'db>,
154    /// Arena of allocated lowered blocks.
155    pub blocks: Blocks<'db>,
156    /// function parameters, including implicits.
157    pub parameters: Vec<VariableId>,
158}
159
160impl<'db> Index<StatementLocation> for Lowered<'db> {
161    type Output = Statement<'db>;
162
163    fn index(&self, location: StatementLocation) -> &Self::Output {
164        &self.blocks[location]
165    }
166}
167
168/// Remapping of lowered variable ids. Useful for convergence of branches.
169#[derive(Clone, Debug, Default, PartialEq, Eq)]
170pub struct VarRemapping<'db> {
171    /// Map from new_var to old_var (since new_var cannot appear twice, but old_var can).
172    pub remapping: OrderedHashMap<VariableId, VarUsage<'db>>,
173}
174impl<'db> Deref for VarRemapping<'db> {
175    type Target = OrderedHashMap<VariableId, VarUsage<'db>>;
176
177    fn deref(&self) -> &Self::Target {
178        &self.remapping
179    }
180}
181impl<'db> DerefMut for VarRemapping<'db> {
182    fn deref_mut(&mut self) -> &mut Self::Target {
183        &mut self.remapping
184    }
185}
186
187/// A block of statements.
188#[derive(Clone, Debug, PartialEq, Eq)]
189pub struct Block<'db> {
190    /// Statements sequence running one after the other in the block, in a linear flow.
191    pub statements: Vec<Statement<'db>>,
192    /// Describes how this block ends.
193    pub end: BlockEnd<'db>,
194}
195impl<'db> Default for Block<'db> {
196    fn default() -> Self {
197        Self { statements: Default::default(), end: BlockEnd::NotSet }
198    }
199}
200impl<'db> Block<'db> {
201    pub fn is_set(&self) -> bool {
202        !matches!(self.end, BlockEnd::NotSet)
203    }
204}
205
206/// Describes what happens to the program flow at the end of a [`Block`].
207#[derive(Clone, Debug, PartialEq, Eq)]
208pub enum BlockEnd<'db> {
209    /// The block was created but still needs to be populated. Block must not be in this state in
210    /// the end of the lowering phase.
211    NotSet,
212    /// This block ends with a `return` statement, exiting the function.
213    Return(Vec<VarUsage<'db>>, LocationId<'db>),
214    /// This block ends with a panic.
215    Panic(VarUsage<'db>),
216    /// This block ends with a jump to a different block.
217    Goto(BlockId, VarRemapping<'db>),
218    Match {
219        info: MatchInfo<'db>,
220    },
221}
222
223impl<'db> BlockEnd<'db> {
224    /// Returns the location of this block end, if available.
225    pub fn location(&self) -> Option<LocationId<'db>> {
226        match self {
227            BlockEnd::Return(_, location) => Some(*location),
228            BlockEnd::Panic(var) => Some(var.location),
229            BlockEnd::Match { info } => Some(*info.location()),
230            BlockEnd::Goto(_, _) | BlockEnd::NotSet => None,
231        }
232    }
233}
234
235/// Lowered variable representation.
236#[derive(Clone, Debug, PartialEq, Eq)]
237pub struct Variable<'db> {
238    /// Semantic type of the variable.
239    pub ty: semantic::TypeId<'db>,
240    /// Location of the variable.
241    pub location: LocationId<'db>,
242    /// The semantic type info of the variable.
243    pub info: TypeInfo<'db>,
244}
245
246impl<'db> DebugWithDb<'db> for Variable<'db> {
247    type Db = LoweredFormatter<'db>;
248
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _ctx: &Self::Db) -> std::fmt::Result {
250        write!(f, "Variable({:?})", self.ty)
251    }
252}
253
254impl<'db> Variable<'db> {
255    pub fn new(
256        db: &'db dyn Database,
257        ctx: ImplLookupContextId<'db>,
258        ty: semantic::TypeId<'db>,
259        location: LocationId<'db>,
260    ) -> Self {
261        Self { ty, location, info: db.type_info(ctx, ty) }
262    }
263
264    /// Returns a new variable with the type, with info calculated with the default context.
265    pub fn with_default_context(
266        db: &'db dyn Database,
267        ty: semantic::TypeId<'db>,
268        location: LocationId<'db>,
269    ) -> Self {
270        Self {
271            ty,
272            location,
273            info: TypeInfo {
274                copyable: db.copyable(ty),
275                droppable: db.droppable(ty),
276                destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
277                    concrete_destruct_trait(db, ty),
278                ))),
279                panic_destruct_impl: Err(InferenceError::Ambiguity(Ambiguity::WillNotInfer(
280                    concrete_panic_destruct_trait(db, ty),
281                ))),
282            },
283        }
284    }
285}
286
287/// Lowered statement.
288#[derive(Clone, Debug, PartialEq, Eq)]
289pub enum Statement<'db> {
290    // Values.
291    Const(StatementConst<'db>),
292
293    // Flow control.
294    Call(StatementCall<'db>),
295
296    // Structs (including tuples).
297    StructConstruct(StatementStructConstruct<'db>),
298    StructDestructure(StatementStructDestructure<'db>),
299
300    // Enums.
301    EnumConstruct(StatementEnumConstruct<'db>),
302
303    Snapshot(StatementSnapshot<'db>),
304    Desnap(StatementDesnap<'db>),
305
306    // Boxing.
307    IntoBox(StatementIntoBox<'db>),
308    Unbox(StatementUnbox<'db>),
309}
310impl<'db> Statement<'db> {
311    pub fn inputs(&self) -> &[VarUsage<'db>] {
312        match &self {
313            Statement::Const(_stmt) => &[],
314            Statement::Call(stmt) => stmt.inputs.as_slice(),
315            Statement::StructConstruct(stmt) => stmt.inputs.as_slice(),
316            Statement::StructDestructure(stmt) => std::slice::from_ref(&stmt.input),
317            Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.input),
318            Statement::Snapshot(stmt) => std::slice::from_ref(&stmt.input),
319            Statement::Desnap(stmt) => std::slice::from_ref(&stmt.input),
320            Statement::IntoBox(stmt) => std::slice::from_ref(&stmt.input),
321            Statement::Unbox(stmt) => std::slice::from_ref(&stmt.input),
322        }
323    }
324
325    pub fn inputs_mut(&mut self) -> &mut [VarUsage<'db>] {
326        match self {
327            Statement::Const(_stmt) => &mut [],
328            Statement::Call(stmt) => stmt.inputs.as_mut_slice(),
329            Statement::StructConstruct(stmt) => stmt.inputs.as_mut_slice(),
330            Statement::StructDestructure(stmt) => std::slice::from_mut(&mut stmt.input),
331            Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.input),
332            Statement::Snapshot(stmt) => std::slice::from_mut(&mut stmt.input),
333            Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.input),
334            Statement::IntoBox(stmt) => std::slice::from_mut(&mut stmt.input),
335            Statement::Unbox(stmt) => std::slice::from_mut(&mut stmt.input),
336        }
337    }
338
339    pub fn outputs(&self) -> &[VariableId] {
340        match self {
341            Statement::Const(stmt) => std::slice::from_ref(&stmt.output),
342            Statement::Call(stmt) => stmt.outputs.as_slice(),
343            Statement::StructConstruct(stmt) => std::slice::from_ref(&stmt.output),
344            Statement::StructDestructure(stmt) => stmt.outputs.as_slice(),
345            Statement::EnumConstruct(stmt) => std::slice::from_ref(&stmt.output),
346            Statement::Snapshot(stmt) => stmt.outputs.as_slice(),
347            Statement::Desnap(stmt) => std::slice::from_ref(&stmt.output),
348            Statement::IntoBox(stmt) => std::slice::from_ref(&stmt.output),
349            Statement::Unbox(stmt) => std::slice::from_ref(&stmt.output),
350        }
351    }
352
353    pub fn outputs_mut(&mut self) -> &mut [VariableId] {
354        match self {
355            Statement::Const(stmt) => std::slice::from_mut(&mut stmt.output),
356            Statement::Call(stmt) => stmt.outputs.as_mut_slice(),
357            Statement::StructConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
358            Statement::StructDestructure(stmt) => stmt.outputs.as_mut_slice(),
359            Statement::EnumConstruct(stmt) => std::slice::from_mut(&mut stmt.output),
360            Statement::Snapshot(stmt) => stmt.outputs.as_mut_slice(),
361            Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.output),
362            Statement::IntoBox(stmt) => std::slice::from_mut(&mut stmt.output),
363            Statement::Unbox(stmt) => std::slice::from_mut(&mut stmt.output),
364        }
365    }
366    pub fn location(&self) -> Option<LocationId<'db>> {
367        // TODO(Gil): Add location to all statements.
368        match &self {
369            Statement::Const(_) => None,
370            Statement::Call(stmt) => Some(stmt.location),
371            Statement::StructConstruct(_) => None,
372            Statement::StructDestructure(stmt) => Some(stmt.input.location),
373            Statement::EnumConstruct(stmt) => Some(stmt.input.location),
374            Statement::Snapshot(stmt) => Some(stmt.input.location),
375            Statement::Desnap(stmt) => Some(stmt.input.location),
376            Statement::IntoBox(stmt) => Some(stmt.input.location),
377            Statement::Unbox(stmt) => Some(stmt.input.location),
378        }
379    }
380    pub fn location_mut(&mut self) -> Option<&mut LocationId<'db>> {
381        match self {
382            Statement::Const(_) => None,
383            Statement::Call(stmt) => Some(&mut stmt.location),
384            Statement::StructConstruct(_) => None,
385            Statement::StructDestructure(stmt) => Some(&mut stmt.input.location),
386            Statement::EnumConstruct(stmt) => Some(&mut stmt.input.location),
387            Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
388            Statement::Desnap(stmt) => Some(&mut stmt.input.location),
389            Statement::IntoBox(stmt) => Some(&mut stmt.input.location),
390            Statement::Unbox(stmt) => Some(&mut stmt.input.location),
391        }
392    }
393}
394
395/// A statement that binds a const value to a variable.
396#[derive(Clone, Debug, PartialEq, Eq)]
397pub struct StatementConst<'db> {
398    /// The value of the const.
399    pub value: ConstValueId<'db>,
400    /// The variable to bind the value to.
401    pub output: VariableId,
402    /// Is the const wrapped in a box.
403    pub boxed: bool,
404}
405impl<'db> StatementConst<'db> {
406    /// Creates a new const statement, with the option to wrap the value in a box.
407    pub fn new(value: ConstValueId<'db>, output: VariableId, boxed: bool) -> Self {
408        Self { value, output, boxed }
409    }
410    /// Creates a new const statement, not boxed.
411    pub fn new_flat(value: ConstValueId<'db>, output: VariableId) -> Self {
412        Self::new(value, output, false)
413    }
414    /// Creates a new const statement with the value wrapped in a box.
415    pub fn new_boxed(value: ConstValueId<'db>, output: VariableId) -> Self {
416        Self::new(value, output, true)
417    }
418}
419
420/// A statement that calls a user function.
421#[derive(Clone, Debug, PartialEq, Eq)]
422pub struct StatementCall<'db> {
423    /// A function to "call".
424    pub function: FunctionId<'db>,
425    /// Living variables in current scope to move to the function, as arguments.
426    pub inputs: Vec<VarUsage<'db>>,
427    /// Is the last input a coupon for the function call. See
428    /// [semantic::ExprFunctionCall::coupon_arg] for more information.
429    pub with_coupon: bool,
430    /// New variables to be introduced into the current scope from the function outputs.
431    pub outputs: Vec<VariableId>,
432    /// Is the call to be inlined as part of the specialization wrapper function.
433    pub is_specialization_base_call: bool,
434    /// Location for the call.
435    pub location: LocationId<'db>,
436}
437
438/// A statement that constructs a variant of an enum with a single argument, and binds it to a
439/// variable.
440#[derive(Clone, Debug, PartialEq, Eq)]
441pub struct StatementEnumConstruct<'db> {
442    pub variant: ConcreteVariant<'db>,
443    /// A living variable in current scope to wrap with the variant.
444    pub input: VarUsage<'db>,
445    /// The variable to bind the value to.
446    pub output: VariableId,
447}
448
449/// A statement that constructs a struct (tuple included) into a new variable.
450#[derive(Clone, Debug, PartialEq, Eq)]
451pub struct StatementStructConstruct<'db> {
452    pub inputs: Vec<VarUsage<'db>>,
453    /// The variable to bind the value to.
454    pub output: VariableId,
455}
456
457/// A statement that destructures a struct (tuple included), introducing its elements as new
458/// variables.
459#[derive(Clone, Debug, PartialEq, Eq)]
460pub struct StatementStructDestructure<'db> {
461    /// A living variable in current scope to destructure.
462    pub input: VarUsage<'db>,
463    /// The variables to bind values to.
464    pub outputs: Vec<VariableId>,
465}
466
467/// A statement that takes a snapshot of a variable.
468#[derive(Clone, Debug, PartialEq, Eq)]
469pub struct StatementSnapshot<'db> {
470    pub input: VarUsage<'db>,
471    pub outputs: [VariableId; 2],
472}
473impl<'db> StatementSnapshot<'db> {
474    pub fn new(
475        input: VarUsage<'db>,
476        output_original: VariableId,
477        output_snapshot: VariableId,
478    ) -> Self {
479        Self { input, outputs: [output_original, output_snapshot] }
480    }
481    pub fn original(&self) -> VariableId {
482        self.outputs[0]
483    }
484    pub fn snapshot(&self) -> VariableId {
485        self.outputs[1]
486    }
487}
488
489/// A statement that desnaps a variable.
490#[derive(Clone, Debug, PartialEq, Eq)]
491pub struct StatementDesnap<'db> {
492    pub input: VarUsage<'db>,
493    /// The variable to bind the value to.
494    pub output: VariableId,
495}
496
497/// A statement that constructs a box from a value.
498#[derive(Clone, Debug, PartialEq, Eq)]
499pub struct StatementIntoBox<'db> {
500    /// The value to box.
501    pub input: VarUsage<'db>,
502    /// The variable to bind the boxed value to.
503    pub output: VariableId,
504}
505
506/// A statement that unboxes a value.
507#[derive(Clone, Debug, PartialEq, Eq)]
508pub struct StatementUnbox<'db> {
509    /// The boxed value to unbox.
510    pub input: VarUsage<'db>,
511    /// The variable to bind the unboxed value to.
512    pub output: VariableId,
513}
514
515/// An arm of a match statement.
516#[derive(Clone, Debug, PartialEq, Eq)]
517pub struct MatchArm<'db> {
518    /// The selector of the arm.
519    pub arm_selector: MatchArmSelector<'db>,
520
521    /// The block_id where the relevant arm is implemented.
522    pub block_id: BlockId,
523
524    /// The list of variable ids introduced in this arm.
525    pub var_ids: Vec<VariableId>,
526}
527
528/// A statement that calls an extern function with branches, and "calls" a possibly different block
529/// for each branch.
530#[derive(Clone, Debug, PartialEq, Eq)]
531pub struct MatchExternInfo<'db> {
532    // TODO(spapini): ConcreteExternFunctionId once it exists.
533    /// A concrete external function to call.
534    pub function: FunctionId<'db>,
535    /// Living variables in current scope to move to the function, as arguments.
536    pub inputs: Vec<VarUsage<'db>>,
537    /// Match arms. All blocks should have the same rets.
538    /// Order must be identical to the order in the definition of the enum.
539    pub arms: Vec<MatchArm<'db>>,
540    /// Location for the call.
541    pub location: LocationId<'db>,
542}
543
544/// A statement that matches an enum, and "calls" a possibly different block for each branch.
545#[derive(Clone, Debug, PartialEq, Eq)]
546pub struct MatchEnumInfo<'db> {
547    pub concrete_enum_id: ConcreteEnumId<'db>,
548    /// A living variable in current scope to match on.
549    pub input: VarUsage<'db>,
550    /// Match arms. All blocks should have the same rets.
551    /// Order must be identical to the order in the definition of the enum.
552    pub arms: Vec<MatchArm<'db>>,
553    /// Location for the match.
554    pub location: LocationId<'db>,
555}
556/// A statement that matches an index enum for matching on felt252, and "calls" a possibly different
557/// block for each branch.
558#[derive(Clone, Debug, PartialEq, Eq)]
559pub struct MatchEnumValue<'db> {
560    pub num_of_arms: usize,
561
562    /// A living variable in current scope to match on.
563    pub input: VarUsage<'db>,
564    /// Match arms. All blocks should have the same rets.
565    pub arms: Vec<MatchArm<'db>>,
566    /// Location for the match.
567    pub location: LocationId<'db>,
568}
569
570#[derive(Clone, Debug, PartialEq, Eq)]
571pub enum MatchInfo<'db> {
572    Enum(MatchEnumInfo<'db>),
573    Extern(MatchExternInfo<'db>),
574    Value(MatchEnumValue<'db>),
575}
576impl<'db> MatchInfo<'db> {
577    pub fn inputs(&self) -> &[VarUsage<'db>] {
578        match self {
579            MatchInfo::Enum(s) => std::slice::from_ref(&s.input),
580            MatchInfo::Extern(s) => s.inputs.as_slice(),
581            MatchInfo::Value(s) => std::slice::from_ref(&s.input),
582        }
583    }
584
585    pub fn inputs_mut(&mut self) -> &mut [VarUsage<'db>] {
586        match self {
587            MatchInfo::Enum(s) => std::slice::from_mut(&mut s.input),
588            MatchInfo::Extern(s) => s.inputs.as_mut_slice(),
589            MatchInfo::Value(s) => std::slice::from_mut(&mut s.input),
590        }
591    }
592    pub fn arms(&self) -> &[MatchArm<'db>] {
593        match self {
594            MatchInfo::Enum(s) => &s.arms,
595            MatchInfo::Extern(s) => &s.arms,
596            MatchInfo::Value(s) => &s.arms,
597        }
598    }
599    pub fn arms_mut(&mut self) -> &mut [MatchArm<'db>] {
600        match self {
601            MatchInfo::Enum(s) => &mut s.arms,
602            MatchInfo::Extern(s) => &mut s.arms,
603            MatchInfo::Value(s) => &mut s.arms,
604        }
605    }
606    pub fn location(&self) -> &LocationId<'db> {
607        match self {
608            MatchInfo::Enum(s) => &s.location,
609            MatchInfo::Extern(s) => &s.location,
610            MatchInfo::Value(s) => &s.location,
611        }
612    }
613    pub fn location_mut(&mut self) -> &mut LocationId<'db> {
614        match self {
615            MatchInfo::Enum(s) => &mut s.location,
616            MatchInfo::Extern(s) => &mut s.location,
617            MatchInfo::Value(s) => &mut s.location,
618        }
619    }
620}
621
622/// Used in graph algorithms, and describes how to construct the edges in function dependency graph.
623#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
624pub enum DependencyType {
625    /// A function depends on another function if it may call it.
626    Call,
627    /// A function depends on another function if its cost depends on the other function's cost.
628    Cost,
629}
630
631/// The requested lowering stage.
632#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
633pub enum LoweringStage {
634    /// Direct translation from the semantic stage and concretization.
635    Monomorphized,
636    /// After lowering stages that may change the signature of functions, such as `lower_panics`.
637    /// Specifically:
638    /// * Adds `withdraw_gas` calls.
639    /// * Adds panics.
640    /// * Adds destructor calls.
641    /// * scrub units.
642    PreOptimizations,
643    /// Lowering with baseline optimizations - specifically, adds the stages at
644    /// `baseline_optimization_strategy`.
645    PostBaseline,
646    /// Lowering with all of the optimizations - specifically, adds the stages at
647    /// `final_optimization_strategy`.
648    Final,
649}