cairo_lang_lowering/concretize/
mod.rs

1use cairo_lang_diagnostics::Maybe;
2use cairo_lang_semantic::substitution::GenericSubstitution;
3use cairo_lang_utils::{Intern, LookupIntern};
4
5use crate::db::LoweringGroup;
6use crate::ids::{FunctionId, FunctionLongId, GeneratedFunction, SemanticFunctionIdEx};
7use crate::{FlatBlockEnd, FlatLowered, MatchArm, Statement};
8
9/// Rewrites a [FunctionId] with a [GenericSubstitution].
10fn concretize_function(
11    db: &dyn LoweringGroup,
12    substitution: &GenericSubstitution,
13    function: FunctionId,
14) -> Maybe<FunctionId> {
15    match function.lookup_intern(db) {
16        FunctionLongId::Semantic(id) => {
17            // We call `lowered` here in case the function will be substituted to a generated one.
18            Ok(substitution.substitute(db.upcast(), id)?.lowered(db))
19        }
20        FunctionLongId::Generated(GeneratedFunction { parent, key }) => {
21            Ok(FunctionLongId::Generated(GeneratedFunction {
22                parent: substitution.substitute(db.upcast(), parent)?,
23                key,
24            })
25            .intern(db))
26        }
27    }
28}
29
30/// Concretizes a lowered generic function by applying a generic parameter substitution on its
31/// variable types, variants and called functions.
32pub fn concretize_lowered(
33    db: &dyn LoweringGroup,
34    lowered: &mut FlatLowered,
35    substitution: &GenericSubstitution,
36) -> Maybe<()> {
37    // Substitute all types.
38    for (_, var) in lowered.variables.iter_mut() {
39        var.ty = substitution.substitute(db.upcast(), var.ty)?;
40
41        for impl_id in [&mut var.destruct_impl, &mut var.panic_destruct_impl].into_iter().flatten()
42        {
43            *impl_id = substitution.substitute(db.upcast(), *impl_id)?;
44        }
45    }
46    // Substitute all statements.
47    for block in lowered.blocks.iter_mut() {
48        for stmt in block.statements.iter_mut() {
49            match stmt {
50                Statement::Call(stmt) => {
51                    stmt.function = concretize_function(db, substitution, stmt.function)?;
52                }
53                Statement::EnumConstruct(stmt) => {
54                    stmt.variant = substitution.substitute(db.upcast(), stmt.variant.clone())?;
55                }
56                Statement::Const(stmt) => {
57                    stmt.value = substitution.substitute(db.upcast(), stmt.value.clone())?;
58                }
59                Statement::Snapshot(_)
60                | Statement::Desnap(_)
61                | Statement::StructConstruct(_)
62                | Statement::StructDestructure(_) => {}
63            }
64        }
65        if let FlatBlockEnd::Match { info } = &mut block.end {
66            for MatchArm { arm_selector: selector, .. } in match info {
67                crate::MatchInfo::Enum(s) => s.arms.iter_mut(),
68                crate::MatchInfo::Extern(s) => {
69                    s.function = concretize_function(db, substitution, s.function)?;
70                    s.arms.iter_mut()
71                }
72                crate::MatchInfo::Value(s) => s.arms.iter_mut(),
73            } {
74                *selector = substitution.substitute(db.upcast(), selector.clone())?;
75            }
76        }
77    }
78    lowered.signature = substitution.substitute(db.upcast(), lowered.signature.clone())?;
79
80    Ok(())
81}