1#[cfg(test)]
2#[path = "block_generator_test.rs"]
3mod test;
4
5use cairo_lang_diagnostics::Maybe;
6use cairo_lang_filesystem::flag::FlagsGroup;
7use cairo_lang_lowering::BlockId;
8use cairo_lang_lowering::db::LoweringGroup;
9use cairo_lang_lowering::ids::LocationId;
10use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
11use itertools::{chain, enumerate, zip_eq};
12use lowering::analysis::StatementLocation;
13use lowering::{MatchArm, VarUsage};
14use sierra::extensions::lib_func::SierraApChange;
15use sierra::program;
16use {cairo_lang_lowering as lowering, cairo_lang_sierra as sierra};
17
18use crate::block_generator::sierra::ids::ConcreteLibfuncId;
19use crate::db::SierraGenGroup;
20use crate::expr_generator_context::{ExprGenerationResult, ExprGeneratorContext};
21use crate::lifetime::{DropLocation, SierraGenVar, UseLocation};
22use crate::local_variables::MIN_SIZE_FOR_LOCAL_INTO_BOX;
23use crate::pre_sierra::{self, StatementWithLocation};
24use crate::replace_ids::{DebugReplacer, SierraIdReplacer};
25use crate::utils::{
26 branch_align_libfunc_id, const_libfunc_id_by_type, disable_ap_tracking_libfunc_id,
27 drop_libfunc_id, dup_libfunc_id, enable_ap_tracking_libfunc_id,
28 enum_from_bounded_int_libfunc_id, enum_init_libfunc_id, get_concrete_libfunc_id,
29 get_libfunc_signature, into_box_libfunc_id, jump_libfunc_id, jump_statement,
30 local_into_box_libfunc_id, match_enum_libfunc_id, rename_libfunc_id, return_statement,
31 simple_basic_statement, snapshot_take_libfunc_id, struct_construct_libfunc_id,
32 struct_deconstruct_libfunc_id, unbox_libfunc_id,
33};
34
35pub fn generate_block_body_code<'db>(
38 context: &mut ExprGeneratorContext<'db, '_>,
39 block_id: lowering::BlockId,
40 block: &lowering::Block<'db>,
41) -> Maybe<()> {
42 if context.should_disable_ap_tracking(&block_id) {
43 context.set_ap_tracking(false);
44 context.push_statement(simple_basic_statement(
45 disable_ap_tracking_libfunc_id(context.get_db()),
46 &[],
47 &[],
48 ));
49 }
50
51 let drops = context.get_drops();
52
53 add_drop_statements(context, drops, &DropLocation::BeginningOfBlock(block_id))?;
54
55 for (i, statement) in block.statements.iter().enumerate() {
57 let statement_lowering_location = (block_id, i);
58 let statement_cairo_location = statement.location();
59 context.maybe_set_cairo_location(statement_cairo_location);
60 generate_statement_code(context, statement, &statement_lowering_location)?;
61 let drop_location = &DropLocation::PostStatement(statement_lowering_location);
62 add_drop_statements(context, drops, drop_location)?;
63 }
64
65 add_drop_statements(
66 context,
67 drops,
68 &DropLocation::PostStatement((block_id, block.statements.len())),
69 )?;
70
71 Ok(())
72}
73
74fn add_drop_statements<'db>(
77 context: &mut ExprGeneratorContext<'db, '_>,
78 drops: &OrderedHashMap<DropLocation, Vec<SierraGenVar>>,
79 drop_location: &DropLocation,
80) -> Maybe<()> {
81 let Some(vars) = drops.get(drop_location) else { return Ok(()) };
82
83 for sierra_gen_var in vars {
84 let sierra_var = context.get_sierra_variable(*sierra_gen_var);
85 let ty = context.get_variable_sierra_type(*sierra_gen_var)?;
86 context.push_statement(simple_basic_statement(
87 drop_libfunc_id(context.get_db(), ty),
88 &[sierra_var],
89 &[],
90 ));
91 }
92
93 Ok(())
94}
95
96enum BlockGenStackElement<'db> {
98 Block(BlockId),
100 Statement(pre_sierra::Statement<'db>),
102 Config { starting_cairo_location: Option<LocationId<'db>>, ap_tracking_state: bool },
104}
105
106pub fn generate_function_result<'db>(
110 mut context: ExprGeneratorContext<'db, '_>,
111) -> Maybe<ExprGenerationResult<'db>> {
112 let mut block_gen_stack = vec![BlockGenStackElement::Block(BlockId::root())];
113 while let Some(element) = block_gen_stack.pop() {
114 match element {
115 BlockGenStackElement::Block(block_id) => {
116 generate_block_code(&mut context, &mut block_gen_stack, block_id)?
117 }
118 BlockGenStackElement::Statement(statement) => context.push_statement(statement),
119 BlockGenStackElement::Config { starting_cairo_location, ap_tracking_state } => {
120 context.curr_cairo_location = starting_cairo_location;
121 context.set_ap_tracking(ap_tracking_state);
122 }
123 }
124 }
125 Ok(context.result())
126}
127
128fn generate_block_code<'db>(
133 context: &mut ExprGeneratorContext<'db, '_>,
134 block_gen_stack: &mut Vec<BlockGenStackElement<'db>>,
135 block_id: BlockId,
136) -> Maybe<()> {
137 let block = context.get_lowered_block(block_id);
138 let statement_location: StatementLocation = (block_id, block.statements.len());
139
140 generate_block_body_code(context, block_id, block)?;
141
142 match &block.end {
143 lowering::BlockEnd::Return(returned_variables, _location) => {
144 generate_return_code(context, returned_variables, &statement_location)?;
145 }
146 lowering::BlockEnd::Panic(_) => {
147 unreachable!("Panics should have been stripped in a previous phase.")
148 }
149 lowering::BlockEnd::Goto(target_block_id, remapping) => {
150 let StatementWithLocation { statement: push_values_statement, location } =
151 generate_push_values_statement_for_remapping(
152 context,
153 statement_location,
154 remapping,
155 )?;
156 context.maybe_set_cairo_location(location);
157 context.push_statement(push_values_statement);
158
159 if *target_block_id == block_id.next_block_id() {
160 let label = pre_sierra::Statement::Label(pre_sierra::Label {
161 id: *context.block_label(*target_block_id),
162 });
163 context.push_statement(label);
164 block_gen_stack.push(BlockGenStackElement::Block(*target_block_id));
165 } else {
166 let jump = jump_statement(
167 jump_libfunc_id(context.get_db()),
168 *context.block_label(*target_block_id),
169 );
170 context.push_statement(jump);
171 }
172 }
173 lowering::BlockEnd::NotSet => unreachable!(),
174 lowering::BlockEnd::Match { info } => {
176 let statement_location = (block_id, block.statements.len());
177 let statement_cairo_location = info.location();
178 if context.should_enable_ap_tracking(&block_id) {
179 context.set_ap_tracking(true);
180 context.push_statement(simple_basic_statement(
181 enable_ap_tracking_libfunc_id(context.get_db()),
182 &[],
183 &[],
184 ));
185 }
186
187 context.maybe_set_cairo_location(Some(*statement_cairo_location));
188
189 match info {
190 lowering::MatchInfo::Extern(s) => {
191 generate_match_extern_code(context, block_gen_stack, s, &statement_location)
192 }
193 lowering::MatchInfo::Enum(s) => {
194 generate_match_enum_code(context, block_gen_stack, s, &statement_location)
195 }
196 lowering::MatchInfo::Value(s) => {
197 generate_match_value_code(context, block_gen_stack, s, &statement_location)
198 }
199 }?;
200 }
201 }
202 Ok(())
203}
204
205fn generate_push_values_statement_for_remapping<'db, 'mt>(
207 context: &mut ExprGeneratorContext<'db, 'mt>,
208 statement_location: (lowering::BlockId, usize),
209 remapping: &lowering::VarRemapping<'db>,
210) -> Maybe<pre_sierra::StatementWithLocation<'db>> {
211 let mut push_values = Vec::<pre_sierra::PushValue>::new();
212 for (idx, (output, inner_output)) in remapping.iter().enumerate() {
213 let ty = context.get_variable_sierra_type(*inner_output)?;
214 let var_on_stack_ty = context.get_variable_sierra_type(*output)?;
215
216 if ty != var_on_stack_ty {
217 let debug_replacer = DebugReplacer { db: context.get_db() };
218 panic!(
219 "Internal compiler error: Inconsistent types in \
220 generate_push_values_statement_for_remapping(): ty: `{}`, var_on_stack_ty: `{}`",
221 debug_replacer.replace_type_id(&ty),
222 debug_replacer.replace_type_id(&var_on_stack_ty),
223 );
224 }
225 let dup = !context.is_last_use(&UseLocation { statement_location, idx });
226 push_values.push(pre_sierra::PushValue {
227 var: context.get_sierra_variable(*inner_output),
228 var_on_stack: context.get_sierra_variable(*output),
229 ty,
230 dup,
231 })
232 }
233 let location = remapping.iter().next_back().map(|(_, inner_output)| inner_output.location);
234 Ok(StatementWithLocation {
235 statement: pre_sierra::Statement::PushValues(push_values),
236 location,
237 })
238}
239
240pub fn generate_return_code<'db>(
245 context: &mut ExprGeneratorContext<'db, '_>,
246 returned_variables: &[lowering::VarUsage<'db>],
247 statement_location: &StatementLocation,
248) -> Maybe<()> {
249 let mut return_variables_on_stack = vec![];
251 let mut push_values = vec![];
252
253 for (idx, returned_variable) in returned_variables.iter().enumerate() {
254 let use_location = UseLocation { statement_location: *statement_location, idx };
255 let should_dup = should_dup(context, &use_location);
256 let var = context.get_sierra_variable(*returned_variable);
257 let return_variable_on_stack = if should_dup {
258 context.allocate_sierra_variable(returned_variable.var_id)
259 } else {
260 var.clone()
261 };
262 return_variables_on_stack.push(return_variable_on_stack.clone());
263 push_values.push(pre_sierra::PushValue {
264 var,
265 var_on_stack: return_variable_on_stack,
266 ty: context.get_variable_sierra_type(*returned_variable)?,
267 dup: should_dup,
268 });
269 }
270 let location = returned_variables.last().map(|var| var.location);
271 context.maybe_set_cairo_location(location);
272 context.push_statement(pre_sierra::Statement::PushValues(push_values));
273 context.push_statement(return_statement(return_variables_on_stack));
274 Ok(())
275}
276
277pub fn generate_statement_code<'db>(
279 context: &mut ExprGeneratorContext<'db, '_>,
280 statement: &lowering::Statement<'db>,
281 statement_location: &StatementLocation,
282) -> Maybe<()> {
283 match statement {
284 lowering::Statement::Const(statement_literal) => {
285 generate_statement_const_code(context, statement_literal)
286 }
287 lowering::Statement::Call(statement_call) => {
288 generate_statement_call_code(context, statement_call, statement_location)
289 }
290 lowering::Statement::EnumConstruct(statement_enum_construct) => {
291 generate_statement_enum_construct(context, statement_enum_construct, statement_location)
292 }
293 lowering::Statement::StructConstruct(statement) => {
294 generate_statement_struct_construct_code(context, statement, statement_location)
295 }
296 lowering::Statement::StructDestructure(statement) => {
297 generate_statement_struct_destructure_code(context, statement, statement_location)
298 }
299 lowering::Statement::Snapshot(statement) => {
300 generate_statement_snapshot(context, statement, statement_location)
301 }
302 lowering::Statement::Desnap(statement) => {
303 generate_statement_desnap(context, statement, statement_location)
304 }
305 lowering::Statement::IntoBox(statement) => {
306 generate_statement_into_box(context, statement, statement_location)
307 }
308 lowering::Statement::Unbox(statement) => {
309 generate_statement_unbox(context, statement, statement_location)
310 }
311 }
312}
313
314fn generate_statement_const_code<'db>(
316 context: &mut ExprGeneratorContext<'db, '_>,
317 statement: &lowering::StatementConst<'db>,
318) -> Maybe<()> {
319 let output_var = context.get_sierra_variable(statement.output);
320 context.push_statement(simple_basic_statement(
321 const_libfunc_id_by_type(context.get_db(), statement.value, statement.boxed),
322 &[],
323 &[output_var],
324 ));
325 Ok(())
326}
327
328fn generate_statement_call_code<'db>(
330 context: &mut ExprGeneratorContext<'db, '_>,
331 statement: &lowering::StatementCall<'db>,
332 statement_location: &StatementLocation,
333) -> Maybe<()> {
334 let (body, libfunc_id) =
336 get_concrete_libfunc_id(context.get_db(), statement.function, statement.with_coupon);
337 let libfunc_signature = get_libfunc_signature(context.get_db(), &libfunc_id);
339 let [branch_signature] = &libfunc_signature.branch_signatures[..] else {
340 panic!(
341 "Unexpected branches in '{}'.",
342 DebugReplacer { db: context.get_db() }.replace_libfunc_id(&libfunc_id)
343 );
344 };
345 if matches!(branch_signature.ap_change, SierraApChange::Unknown) {
346 context.set_ap_tracking(false)
347 }
348
349 if body.is_some() {
350 let mut args_on_stack: Vec<sierra::ids::VarId> = vec![];
352 let mut push_values_vec: Vec<pre_sierra::PushValue> = vec![];
353
354 for (idx, var_usage) in statement.inputs.iter().enumerate() {
355 let use_location = UseLocation { statement_location: *statement_location, idx };
356 let should_dup = should_dup(context, &use_location);
357 let var = context.get_sierra_variable(var_usage.var_id);
358 let arg_on_stack = if should_dup {
359 context.allocate_sierra_variable(var_usage.var_id)
360 } else {
361 var.clone()
362 };
363 push_values_vec.push(pre_sierra::PushValue {
364 var,
365 var_on_stack: arg_on_stack.clone(),
366 ty: context.get_variable_sierra_type(var_usage.var_id)?,
367 dup: should_dup,
368 });
369 args_on_stack.push(arg_on_stack);
370 }
371
372 context.push_statement(pre_sierra::Statement::PushValues(push_values_vec));
374 let call_stmt = simple_basic_statement(
376 libfunc_id,
377 &args_on_stack,
378 &context.get_sierra_variables(&statement.outputs),
379 );
380 context.push_statement(call_stmt);
381 } else {
382 assert!(!statement.with_coupon, "Extern functions cannot have a __coupon__ argument.");
383 let inputs_after_dup =
385 maybe_add_dup_statements(context, statement_location, &statement.inputs)?;
386 let stmt = simple_basic_statement(
387 libfunc_id,
388 &inputs_after_dup,
389 &context.get_sierra_variables(&statement.outputs),
390 );
391 context.push_statement(stmt);
392 }
393 Ok(())
394}
395
396fn should_dup<'db>(
398 context: &mut ExprGeneratorContext<'db, '_>,
399 use_location: &UseLocation,
400) -> bool {
401 !context.is_last_use(use_location)
402}
403
404fn maybe_add_dup_statements<'db>(
407 context: &mut ExprGeneratorContext<'db, '_>,
408 statement_location: &StatementLocation,
409 lowering_vars: &[VarUsage<'db>],
410) -> Maybe<Vec<sierra::ids::VarId>> {
411 lowering_vars
412 .iter()
413 .enumerate()
414 .map(|(idx, lowering_var)| {
415 maybe_add_dup_statement(context, statement_location, idx, lowering_var)
416 })
417 .collect()
418}
419
420fn maybe_add_dup_statement<'db>(
423 context: &mut ExprGeneratorContext<'db, '_>,
424 statement_location: &StatementLocation,
425 idx: usize,
426 lowering_var: &VarUsage<'db>,
427) -> Maybe<sierra::ids::VarId> {
428 let sierra_var = context.get_sierra_variable(*lowering_var);
429
430 if context.is_last_use(&UseLocation { statement_location: *statement_location, idx }) {
432 Ok(sierra_var)
434 } else {
435 let ty = context.get_variable_sierra_type(*lowering_var)?;
436 let dup_var = context.allocate_sierra_variable(lowering_var.var_id);
437 context.push_statement(simple_basic_statement(
438 dup_libfunc_id(context.get_db(), ty),
439 std::slice::from_ref(&sierra_var),
440 &[sierra_var.clone(), dup_var.clone()],
441 ));
442 Ok(dup_var)
443 }
444}
445
446fn generate_match_extern_code<'db>(
448 context: &mut ExprGeneratorContext<'db, '_>,
449 block_gen_stack: &mut Vec<BlockGenStackElement<'db>>,
450 match_info: &lowering::MatchExternInfo<'db>,
451 statement_location: &StatementLocation,
452) -> Maybe<()> {
453 let args = maybe_add_dup_statements(context, statement_location, &match_info.inputs)?;
455 let (_function_long_id, libfunc_id) =
457 get_concrete_libfunc_id(context.get_db(), match_info.function, false);
458
459 generate_match_code(context, block_gen_stack, libfunc_id, args, &match_info.arms)
460}
461fn generate_match_code<'db>(
464 context: &mut ExprGeneratorContext<'db, '_>,
465 block_gen_stack: &mut Vec<BlockGenStackElement<'db>>,
466 libfunc_id: ConcreteLibfuncId,
467 args: Vec<sierra::ids::VarId>,
468 arms: &[lowering::MatchArm<'db>],
469) -> Maybe<()> {
470 let arm_labels: Vec<(pre_sierra::Statement<'_>, pre_sierra::LabelId<'_>)> =
472 (1..arms.len()).map(|_i| context.new_label()).collect();
473 let (end_label, _) = context.new_label();
475
476 let arm_targets: Vec<program::GenBranchTarget<pre_sierra::LabelId<'_>>> = if arms.is_empty() {
478 vec![]
479 } else {
480 chain!(
481 [program::GenBranchTarget::Fallthrough],
482 arm_labels
483 .iter()
484 .map(|(_statement, label_id)| program::GenBranchTarget::Statement(*label_id)),
485 )
486 .collect()
487 };
488
489 let branches: Vec<_> = zip_eq(arms, arm_targets)
490 .map(|(arm, target)| program::GenBranchInfo {
491 target,
492 results: context.get_sierra_variables(&arm.var_ids),
493 })
494 .collect();
495
496 context.push_statement(pre_sierra::Statement::Sierra(program::GenStatement::Invocation(
498 program::GenInvocation { libfunc_id, args, branches },
499 )));
500
501 let starting_cairo_location = context.curr_cairo_location.take();
502 let ap_tracking_state = context.get_ap_tracking();
503 let require_branch_aligns = arms.len() > 1;
505
506 block_gen_stack.push(BlockGenStackElement::Statement(end_label));
507 for (i, MatchArm { arm_selector: _, block_id, var_ids: _ }) in enumerate(arms).rev() {
509 block_gen_stack.push(BlockGenStackElement::Block(*block_id));
510 if require_branch_aligns {
511 block_gen_stack.push(BlockGenStackElement::Statement(simple_basic_statement(
512 branch_align_libfunc_id(context.get_db()),
513 &[],
514 &[],
515 )));
516 }
517 if i > 0 {
518 block_gen_stack.push(BlockGenStackElement::Statement(arm_labels[i - 1].0.clone()));
519 }
520 block_gen_stack
521 .push(BlockGenStackElement::Config { starting_cairo_location, ap_tracking_state });
522 }
523 Ok(())
524}
525
526fn generate_statement_enum_construct<'db>(
528 context: &mut ExprGeneratorContext<'db, '_>,
529 statement: &lowering::StatementEnumConstruct<'db>,
530 statement_location: &StatementLocation,
531) -> Maybe<()> {
532 let input = maybe_add_dup_statement(context, statement_location, 0, &statement.input)?;
533 let stmt = simple_basic_statement(
534 enum_init_libfunc_id(
535 context.get_db(),
536 context.get_variable_sierra_type(statement.output)?,
537 statement.variant.idx,
538 ),
539 &[input],
540 &[context.get_sierra_variable(statement.output)],
541 );
542 context.push_statement(stmt);
543 Ok(())
544}
545
546fn generate_statement_struct_construct_code<'db>(
548 context: &mut ExprGeneratorContext<'db, '_>,
549 statement: &lowering::StatementStructConstruct<'db>,
550 statement_location: &StatementLocation,
551) -> Maybe<()> {
552 let inputs = maybe_add_dup_statements(context, statement_location, &statement.inputs)?;
553 let stmt = simple_basic_statement(
554 struct_construct_libfunc_id(
555 context.get_db(),
556 context.get_variable_sierra_type(statement.output)?,
557 ),
558 &inputs,
559 &[context.get_sierra_variable(statement.output)],
560 );
561 context.push_statement(stmt);
562 Ok(())
563}
564
565fn generate_statement_into_box<'db>(
567 context: &mut ExprGeneratorContext<'db, '_>,
568 statement: &lowering::StatementIntoBox<'db>,
569 statement_location: &StatementLocation,
570) -> Maybe<()> {
571 let input = maybe_add_dup_statement(context, statement_location, 0, &statement.input)?;
572 let var_id = statement.input.var_id;
573 let ty = context.get_variable_sierra_type(var_id)?;
574 let db = context.get_db();
575
576 let use_local_into_box = db.flag_future_sierra()
577 && context.is_fp_relative(var_id)
578 && db.type_size(context.get_lowered_variable(var_id).ty) >= MIN_SIZE_FOR_LOCAL_INTO_BOX;
579 let libfunc_id = if use_local_into_box {
580 local_into_box_libfunc_id(db, ty)
581 } else {
582 into_box_libfunc_id(db, ty)
583 };
584 let stmt = simple_basic_statement(
585 libfunc_id,
586 &[input],
587 &[context.get_sierra_variable(statement.output)],
588 );
589 context.push_statement(stmt);
590 Ok(())
591}
592
593fn generate_statement_unbox<'db>(
595 context: &mut ExprGeneratorContext<'db, '_>,
596 statement: &lowering::StatementUnbox<'db>,
597 statement_location: &StatementLocation,
598) -> Maybe<()> {
599 let input = maybe_add_dup_statement(context, statement_location, 0, &statement.input)?;
600 let stmt = simple_basic_statement(
601 unbox_libfunc_id(context.get_db(), context.get_variable_sierra_type(statement.output)?),
602 &[input],
603 &[context.get_sierra_variable(statement.output)],
604 );
605 context.push_statement(stmt);
606 Ok(())
607}
608
609fn generate_statement_struct_destructure_code<'db>(
611 context: &mut ExprGeneratorContext<'db, '_>,
612 statement: &lowering::StatementStructDestructure<'db>,
613 statement_location: &StatementLocation,
614) -> Maybe<()> {
615 let input = maybe_add_dup_statement(context, statement_location, 0, &statement.input)?;
616 let stmt = simple_basic_statement(
617 struct_deconstruct_libfunc_id(
618 context.get_db(),
619 context.get_variable_sierra_type(statement.input.var_id)?,
620 )?,
621 &[input],
622 &context.get_sierra_variables(&statement.outputs),
623 );
624 context.push_statement(stmt);
625 Ok(())
626}
627
628fn generate_match_value_code<'db>(
632 context: &mut ExprGeneratorContext<'db, '_>,
633 block_gen_stack: &mut Vec<BlockGenStackElement<'db>>,
634 match_info: &lowering::MatchEnumValue<'db>,
635 statement_location: &StatementLocation,
636) -> Maybe<()> {
637 let bounded_int = maybe_add_dup_statement(context, statement_location, 0, &match_info.input)?;
639
640 let concrete_enum_type = context.get_db().get_index_enum_type_id(match_info.num_of_arms)?;
642 let enum_var = context.allocate_sierra_variable(match_info.input.var_id);
643 context.push_statement(simple_basic_statement(
644 enum_from_bounded_int_libfunc_id(context.get_db(), concrete_enum_type.clone()),
645 &[bounded_int],
646 std::slice::from_ref(&enum_var),
647 ));
648
649 let libfunc_id = match_enum_libfunc_id(context.get_db(), concrete_enum_type.clone())?;
650
651 let args = vec![enum_var];
652 generate_match_code(context, block_gen_stack, libfunc_id, args, &match_info.arms)
653}
654
655fn generate_match_enum_code<'db>(
657 context: &mut ExprGeneratorContext<'db, '_>,
658 block_gen_stack: &mut Vec<BlockGenStackElement<'db>>,
659 match_info: &lowering::MatchEnumInfo<'db>,
660 statement_location: &StatementLocation,
661) -> Maybe<()> {
662 let matched_enum = maybe_add_dup_statement(context, statement_location, 0, &match_info.input)?;
664 let concrete_enum_type = context.get_variable_sierra_type(match_info.input)?;
666 let libfunc_id = match_enum_libfunc_id(context.get_db(), concrete_enum_type)?;
667
668 let args = vec![matched_enum];
669 generate_match_code(context, block_gen_stack, libfunc_id, args, &match_info.arms)
670}
671
672fn generate_statement_snapshot<'db>(
674 context: &mut ExprGeneratorContext<'db, '_>,
675 statement: &lowering::StatementSnapshot<'db>,
676 statement_location: &StatementLocation,
677) -> Maybe<()> {
678 let input = maybe_add_dup_statement(context, statement_location, 0, &statement.input)?;
680
681 let ty = context.get_variable_sierra_type(statement.input.var_id)?;
682 let func = snapshot_take_libfunc_id(context.get_db(), ty);
683 let stmt = simple_basic_statement(
684 func,
685 &[input],
686 &[
687 context.get_sierra_variable(statement.original()),
688 context.get_sierra_variable(statement.snapshot()),
689 ],
690 );
691 context.push_statement(stmt);
692 Ok(())
693}
694
695fn generate_statement_desnap<'db>(
697 context: &mut ExprGeneratorContext<'db, '_>,
698 statement: &lowering::StatementDesnap<'db>,
699 statement_location: &StatementLocation,
700) -> Maybe<()> {
701 let inputs_after_dup =
703 maybe_add_dup_statements(context, statement_location, &[statement.input])?;
704 let rename_stmt = simple_basic_statement(
705 rename_libfunc_id(
706 context.get_db(),
707 context.get_variable_sierra_type(statement.input.var_id)?,
708 ),
709 &inputs_after_dup,
710 &[context.get_sierra_variable(statement.output)],
711 );
712 context.push_statement(rename_stmt);
713 Ok(())
714}