leo_passes/const_propagation/mod.rs
1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use crate::Pass;
18
19use leo_ast::ProgramReconstructor as _;
20use leo_errors::Result;
21use leo_span::{Span, Symbol};
22
23mod ast;
24
25mod program;
26
27mod visitor;
28pub use visitor::ConstPropagationVisitor;
29
30pub struct ConstPropagationOutput {
31 /// Something about the program was actually changed during the pass.
32 pub changed: bool,
33 /// A const declaration whose RHS was not able to be evaluated.
34 pub const_not_evaluated: Option<Span>,
35 /// An array index which was not able to be evaluated.
36 pub array_index_not_evaluated: Option<Span>,
37 /// An array length which was not able to be evaluated.
38 pub array_length_not_evaluated: Option<Span>,
39 /// A repeat expression count which was not able to be evaluated.
40 pub repeat_count_not_evaluated: Option<Span>,
41}
42
43/// A pass to perform const propagation and folding.
44///
45/// This pass should be used in conjunction with the Unroller so that
46/// loop bounds and consts in loop bodies can be evaluated.
47///
48/// Any of these expressions:
49/// 1. unary operation,
50/// 2. binary operation,
51/// 3. core functions other than cheat codes, mapping ops, or rand functions,
52///
53/// whose arguments are consts or literals will be subject to constant folding.
54/// The ternary conditional operator will also be folded if its condition is
55/// a constant or literal.
56///
57/// This includes the LHS of assignment statements which include array indices.
58pub struct ConstPropagation;
59
60impl Pass for ConstPropagation {
61 type Input = ();
62 type Output = ConstPropagationOutput;
63
64 const NAME: &str = "ConstPropagation";
65
66 fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
67 let ast = std::mem::take(&mut state.ast);
68
69 let mut visitor = ConstPropagationVisitor {
70 state,
71 program: Symbol::intern(""),
72 module: vec![],
73 changed: false,
74 const_not_evaluated: None,
75 array_index_not_evaluated: None,
76 array_length_not_evaluated: None,
77 repeat_count_not_evaluated: None,
78 };
79
80 let ast = ast.map(
81 |program| visitor.reconstruct_program(program),
82 |library| library, // no-op for libraries
83 );
84
85 visitor.state.handler.last_err()?;
86 visitor.state.ast = ast;
87
88 Ok(ConstPropagationOutput {
89 changed: visitor.changed,
90 const_not_evaluated: visitor.const_not_evaluated,
91 array_index_not_evaluated: visitor.array_index_not_evaluated,
92 array_length_not_evaluated: visitor.array_length_not_evaluated,
93 repeat_count_not_evaluated: visitor.repeat_count_not_evaluated,
94 })
95 }
96}
97
98impl<'a> ConstPropagationVisitor<'a> {
99 pub fn new(state: &'a mut crate::CompilerState, program: Symbol) -> Self {
100 ConstPropagationVisitor {
101 state,
102 program,
103 module: vec![],
104 changed: false,
105 const_not_evaluated: None,
106 array_index_not_evaluated: None,
107 array_length_not_evaluated: None,
108 repeat_count_not_evaluated: None,
109 }
110 }
111}