use cairo_lang_semantic::usage::MemberPath;
use cairo_lang_semantic::{Binding, ExprId, PatternId, TypeLongId, VarId};
use cairo_lang_syntax::node::TypedStablePtr;
use cairo_lang_syntax::node::ast::StatementPtr;
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
use cairo_lang_utils::Intern;
use itertools::zip_eq;
use super::block_builder::BlockBuilder;
use super::context::{LoweringContext, LoweringFlowError, VarRequest};
use super::flow_control::create_graph::create_graph_expr_let_else;
use super::flow_control::lower_graph::lower_graph;
use super::generators;
use crate::VarUsage;
use crate::ids::LocationId;
pub fn lower_let_else<'db>(
ctx: &mut LoweringContext<'db, '_>,
builder: &mut BlockBuilder<'db>,
pattern_id: PatternId,
expr: ExprId,
else_clause: ExprId,
stable_ptr: &StatementPtr<'db>,
) -> Result<(), LoweringFlowError<'db>> {
let pattern = &ctx.function_body.arenas.patterns[pattern_id];
let variables = pattern.variables(&ctx.function_body.arenas.patterns);
let var_ids_and_stable_ptrs = variables
.iter()
.map(|pattern_var| (VarId::Local(pattern_var.var.id), pattern_var.stable_ptr.untyped()))
.collect();
let graph =
create_graph_expr_let_else(ctx, pattern_id, expr, else_clause, var_ids_and_stable_ptrs);
let lowered_expr = lower_graph(ctx, builder, &graph, ctx.get_location(stable_ptr.untyped()))?;
let reqs = variables
.iter()
.map(|pattern_var| VarRequest {
ty: pattern_var.var.ty,
location: ctx.get_location(pattern_var.stable_ptr.untyped()),
})
.collect();
let output_vars = generators::StructDestructure {
input: lowered_expr.as_var_usage(ctx, builder)?,
var_reqs: reqs,
}
.add(ctx, &mut builder.statements);
for (pattern_var, output_var) in zip_eq(variables, output_vars) {
let sem_var = Binding::LocalVar(pattern_var.var.clone());
ctx.variables.variables[output_var].location =
ctx.get_location(pattern_var.stable_ptr.untyped());
builder.put_semantic(sem_var.id(), output_var);
ctx.semantic_defs.insert(sem_var.id(), sem_var);
}
Ok(())
}
pub fn lower_success_arm_body<'db>(
ctx: &mut LoweringContext<'db, '_>,
mut builder: BlockBuilder<'db>,
vars: &[(VarId<'db>, SyntaxStablePtrId<'db>)],
location: LocationId<'db>,
) -> (BlockBuilder<'db>, VarUsage<'db>) {
log::trace!("Lowering success arm body");
let inputs: Vec<_> = vars
.iter()
.map(|(var_id, stable_ptr)| {
builder
.get_ref_raw(ctx, &MemberPath::Var(*var_id), ctx.get_location(*stable_ptr), None)
.unwrap()
})
.collect();
let tys = inputs.iter().map(|var_usage| ctx.variables[var_usage.var_id].ty).collect();
let tuple_ty = TypeLongId::Tuple(tys).intern(ctx.db);
let tuple_var_usage = generators::StructConstruct { inputs, ty: tuple_ty, location }
.add(ctx, &mut builder.statements);
(builder, tuple_var_usage)
}