mod.rs
 1  // Copyright (C) 2019-2025 ADnet Contributors
 2  // This file is part of the ADL library.
 3  
 4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
16  
17  //! The `ProcessingAsync` pass rewrites `async { ... }` blocks into standalone
18  //! `async function`s. Each block is lifted to a new top-level async function,
19  //! and the block is replaced with a call to that function.
20  //!
21  //! This involves:
22  //! - Capturing all variable and tuple field accesses used inside the block.
23  //! - Filtering out globals and locals (which are handled differently).
24  //! - Generating fresh function inputs for the captured values.
25  //! - Rewriting the block with replacements for captured expressions.
26  //! - Creating a `CallExpression` that invokes the synthesized async function.
27  //!
28  //! If any async blocks were rewritten, this pass will rebuild the symbol table
29  //! and rerun path resolution and type checking to account for the new functions.
30  //!
31  //! # Example
32  //! ```leo
33  //! async transition foo(x: u32) -> Future {
34  //!     return async {
35  //!         assert(x == 1);  
36  //!     };
37  //! }
38  //! ```
39  //! becomes
40  //! ```leo
41  //! async function foo_(x: u32) {
42  //!     assert(x == 1);
43  //! }
44  //!
45  //! transition foo(x: u32) -> Future {
46  //!     return foo_(x);
47  //! }
48  //! ```
49  
50  use crate::{Pass, PathResolution, SymbolTable, SymbolTableCreation, TypeChecking, TypeCheckingInput};
51  
52  use adl_ast::ProgramReconstructor as _;
53  use adl_errors::Result;
54  use adl_span::Symbol;
55  
56  mod ast;
57  
58  mod program;
59  
60  mod visitor;
61  use visitor::*;
62  
63  pub struct ProcessingAsync;
64  
65  impl Pass for ProcessingAsync {
66      type Input = TypeCheckingInput;
67      type Output = ();
68  
69      const NAME: &str = "ProcessingAsync";
70  
71      fn do_pass(input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
72          let mut ast = std::mem::take(&mut state.ast);
73          let mut visitor = ProcessingAsyncVisitor {
74              state,
75              max_inputs: input.max_inputs,
76              current_program: Symbol::intern(""),
77              current_function: Symbol::intern(""),
78              new_async_functions: Vec::new(),
79              modified: false,
80          };
81          ast.ast = visitor.reconstruct_program(ast.ast);
82          visitor.state.handler.last_err()?;
83          visitor.state.ast = ast;
84  
85          if visitor.modified {
86              // If we actually changed anything in the program, then we need to recreate the symbol table and run type
87              // checking again. That's because this pass introduces new `async function`s to the program.
88              visitor.state.symbol_table = SymbolTable::default();
89              PathResolution::do_pass((), state)?;
90              SymbolTableCreation::do_pass((), state)?;
91              TypeChecking::do_pass(input.clone(), state)?;
92          }
93  
94          Ok(())
95      }
96  }