leo_passes/path_resolution/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
17//! A transform pass that resolves AST paths into explicit local or global references
18//! and constructs all local scopes in the symbol table.
19//!
20//! This pass walks the AST and transforms each `Path` from an unresolved, user-written
21//! form into either a local or global target, based on syntactic context and the current
22//! symbol table state. Global paths are resolved to fully qualified `Location`s, while
23//! local paths are resolved to concrete local symbols. Unresolvable paths are reported
24//! as errors.
25//!
26//! In addition to path resolution, this pass is responsible for creating all local
27//! scopes and inserting local bindings (inputs, const parameters, local variables,
28//! loop iterators, etc.) into the symbol table. After this pass completes, the symbol
29//! table contains a complete and accurate representation of all lexical scopes.
30//!
31//! # Key behaviors:
32//! - Paths with qualifiers are always resolved as global paths.
33//! - Unqualified paths are resolved as global or local based on symbol table lookup.
34//! - Global paths are resolved relative to the current module and program context.
35//! - Local scopes are created for functions, blocks, composites, constructors, and loops.
36//! - Local variables are inserted with their declaration kind, but without final types.
37//!
38//! # Pipeline position:
39//! This pass runs after `GlobalVarsCollection` and before `GlobalItemsCollection`.
40//! Subsequent passes (e.g. type checking) assume that all paths are resolved and
41//! that all scopes already exist, and therefore do not create or mutate scopes.
42
43use crate::Pass;
44
45use leo_ast::ProgramReconstructor as _;
46use leo_errors::Result;
47use leo_span::Symbol;
48
49mod ast;
50
51mod program;
52
53mod visitor;
54use visitor::*;
55
56pub struct PathResolution;
57
58impl Pass for PathResolution {
59 type Input = ();
60 type Output = ();
61
62 const NAME: &str = "PathResolution";
63
64 fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
65 let ast = std::mem::take(&mut state.ast);
66 let mut visitor = PathResolutionVisitor { state, program: Symbol::intern(""), module: Vec::new() };
67
68 let ast = ast.map(
69 |program| visitor.reconstruct_program(program),
70 |library| library, // no-op for libraries
71 );
72
73 visitor.state.handler.last_err()?;
74 visitor.state.ast = ast;
75
76 Ok(())
77 }
78}