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 }