cairo_lang_lowering/concretize/
mod.rs

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