leo_passes/type_checking/scope_state.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 indexmap::IndexMap;
18use leo_ast::{Location, Variant};
19use leo_span::Symbol;
20
21pub struct ScopeState {
22 /// The name of the function that we are currently traversing.
23 pub(crate) function: Option<Symbol>,
24 /// The variant of the function that we are currently traversing.
25 pub(crate) variant: Option<Variant>,
26 /// Whether or not the function that we are currently traversing has a return statement.
27 pub(crate) has_return: bool,
28 /// Current program name.
29 pub(crate) program_name: Option<Symbol>,
30 /// Current module name.
31 pub(crate) module_name: Vec<Symbol>,
32 /// Whether or not we are currently traversing a stub.
33 pub(crate) is_stub: bool,
34 /// The futures that must be propagated to an async function.
35 /// We only expect futures in the top level program scope at this stage so just refer to them by their names.
36 pub(crate) futures: IndexMap<Symbol, Location>,
37 /// Whether the finalize caller has called the finalize function.
38 pub(crate) has_called_finalize: bool,
39 /// Whether this function already contains an `async` block.
40 pub(crate) already_contains_an_async_block: bool,
41 /// Whether we are currently traversing a conditional statement.
42 pub(crate) is_conditional: bool,
43 /// Location of most recent external call that produced a future.
44 pub(crate) call_location: Option<Location>,
45 /// Whether we are currently traversing a constructor.
46 pub(crate) is_constructor: bool,
47}
48
49impl ScopeState {
50 /// Initializes a new `ScopeState`.
51 pub fn new() -> Self {
52 Self {
53 function: None,
54 variant: None,
55 has_return: false,
56 program_name: None,
57 module_name: vec![],
58 is_stub: false,
59 futures: IndexMap::new(),
60 has_called_finalize: false,
61 already_contains_an_async_block: false,
62 is_conditional: false,
63 call_location: None,
64 is_constructor: false,
65 }
66 }
67
68 /// Resets the scope state to a valid starting state, before traversing a function or constructor.
69 pub fn reset(&mut self) {
70 self.function = None;
71 self.variant = None;
72 self.has_return = false;
73 self.is_stub = false;
74 self.has_called_finalize = false;
75 self.is_conditional = false;
76 self.call_location = None;
77 self.is_constructor = false;
78 self.already_contains_an_async_block = false;
79 self.futures = IndexMap::new();
80 }
81
82 /// Get the current location.
83 pub fn location(&self) -> Location {
84 let function_path = self
85 .module_name
86 .iter()
87 .cloned()
88 .chain(std::iter::once(
89 self.function.expect("Only call ScopeState::location when visiting a function or function stub."),
90 ))
91 .collect::<Vec<Symbol>>();
92
93 Location::new(
94 self.program_name.expect("Only call ScopeState::location when visiting a function or function stub."),
95 function_path,
96 )
97 }
98}