leo_passes/loop_unrolling/
ast.rs1use leo_ast::{Expression::Literal, interpreter_value::literal_to_value, *};
18
19use leo_errors::LoopUnrollerError;
20
21use super::UnrollingVisitor;
22
23impl AstReconstructor for UnrollingVisitor<'_> {
24 type AdditionalInput = ();
25 type AdditionalOutput = ();
26
27 fn reconstruct_repeat(
29 &mut self,
30 input: RepeatExpression,
31 _additional: &(),
32 ) -> (Expression, Self::AdditionalOutput) {
33 let new_id = self.state.node_builder.next_id();
36 let new_count = self.reconstruct_expression(input.count, &()).0;
37 let el_ty = self.state.type_table.get(&input.expr.id()).expect("guaranteed by type checking");
38 self.state.type_table.insert(new_id, Type::Array(ArrayType::new(el_ty, new_count.clone())));
39 (
40 RepeatExpression {
41 expr: self.reconstruct_expression(input.expr, &()).0,
42 count: new_count,
43 id: new_id,
44 ..input
45 }
46 .into(),
47 Default::default(),
48 )
49 }
50
51 fn reconstruct_block(&mut self, mut input: Block) -> (Block, Self::AdditionalOutput) {
52 self.in_scope(input.id(), |slf| {
53 input.statements = input.statements.into_iter().map(|stmt| slf.reconstruct_statement(stmt).0).collect();
54
55 (input, Default::default())
56 })
57 }
58
59 fn reconstruct_const(&mut self, input: ConstDeclaration) -> (Statement, Self::AdditionalOutput) {
60 (input.into(), Default::default())
61 }
62
63 fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
64 (
65 DefinitionStatement {
66 type_: input.type_.map(|ty| self.reconstruct_type(ty).0),
67 value: self.reconstruct_expression(input.value, &()).0,
68 ..input
69 }
70 .into(),
71 Default::default(),
72 )
73 }
74
75 fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
76 let Literal(start_lit_ref) = &input.start else {
80 self.loop_not_unrolled = Some(input.start.span());
81 return (Statement::Iteration(Box::new(input)), Default::default());
82 };
83
84 let Literal(stop_lit_ref) = &input.stop else {
85 self.loop_not_unrolled = Some(input.stop.span());
86 return (Statement::Iteration(Box::new(input)), Default::default());
87 };
88
89 let resolve_unsuffixed = |lit: &leo_ast::Literal, expr_id| {
91 let mut resolved = lit.clone();
92 if let LiteralVariant::Unsuffixed(s) = &resolved.variant {
93 if let Some(Type::Integer(integer_type)) = self.state.type_table.get(&expr_id) {
94 resolved.variant = LiteralVariant::Integer(integer_type, s.clone());
95 }
96 }
97 resolved
98 };
99
100 let resolved_start_lit = resolve_unsuffixed(start_lit_ref, input.start.id());
102 let resolved_stop_lit = resolve_unsuffixed(stop_lit_ref, input.stop.id());
103
104 let start_value =
106 literal_to_value(&resolved_start_lit, &None).expect("Parsing and type checking guarantee this works.");
107 let stop_value =
108 literal_to_value(&resolved_stop_lit, &None).expect("Parsing and type checking guarantee this works.");
109
110 if start_value.gte(&stop_value).expect("Type checking guarantees these are the same type") {
112 self.emit_err(LoopUnrollerError::loop_range_decreasing(input.stop.span()));
113 }
114
115 self.loop_unrolled = true;
116
117 (self.unroll_iteration_statement(input, start_value, stop_value), Default::default())
119 }
120}