leo_passes/const_propagation/
mod.rs

1// Copyright (C) 2019-2025 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 mut ast = std::mem::take(&mut state.ast);
68        let mut visitor = ConstPropagationVisitor {
69            state,
70            program: Symbol::intern(""),
71            module: vec![],
72            changed: false,
73            const_not_evaluated: None,
74            array_index_not_evaluated: None,
75            array_length_not_evaluated: None,
76            repeat_count_not_evaluated: None,
77        };
78        ast.ast = visitor.reconstruct_program(ast.ast);
79        visitor.state.handler.last_err().map_err(|e| *e)?;
80        visitor.state.ast = ast;
81        Ok(ConstPropagationOutput {
82            changed: visitor.changed,
83            const_not_evaluated: visitor.const_not_evaluated,
84            array_index_not_evaluated: visitor.array_index_not_evaluated,
85            array_length_not_evaluated: visitor.array_length_not_evaluated,
86            repeat_count_not_evaluated: visitor.repeat_count_not_evaluated,
87        })
88    }
89}
90
91impl<'a> ConstPropagationVisitor<'a> {
92    pub fn new(state: &'a mut crate::CompilerState, program: Symbol) -> Self {
93        ConstPropagationVisitor {
94            state,
95            program,
96            module: vec![],
97            changed: false,
98            const_not_evaluated: None,
99            array_index_not_evaluated: None,
100            array_length_not_evaluated: None,
101            repeat_count_not_evaluated: None,
102        }
103    }
104}