From cfee45da8fc71d68e441c8cb17d8277603d29264 Mon Sep 17 00:00:00 2001 From: evan-schott <53463459+evan-schott@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:29:29 -0800 Subject: [PATCH] Add compiler flags for configuring await checker in nested conditionals --- compiler/ast/src/functions/mod.rs | 2 +- compiler/ast/src/stub/function_stub.rs | 61 +++++++++++++------ compiler/ast/src/stub/mod.rs | 2 - compiler/ast/src/types/future.rs | 2 +- compiler/ast/src/types/type_.rs | 8 +-- compiler/compiler/src/compiler.rs | 10 ++- compiler/compiler/src/options.rs | 4 ++ .../type_checker/type_checker_warning.rs | 40 ++++++++++++ leo/cli/commands/build.rs | 6 +- leo/cli/commands/mod.rs | 4 ++ 10 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 errors/src/errors/type_checker/type_checker_warning.rs diff --git a/compiler/ast/src/functions/mod.rs b/compiler/ast/src/functions/mod.rs index 567c530415..b81a64dcb7 100644 --- a/compiler/ast/src/functions/mod.rs +++ b/compiler/ast/src/functions/mod.rs @@ -126,7 +126,7 @@ impl Function { _ => self.output.iter().map(|x| x.to_string()).collect::>().join(","), }; write!(f, "({parameters}) -> {returns} {}", self.block)?; - + Ok(()) } } diff --git a/compiler/ast/src/stub/function_stub.rs b/compiler/ast/src/stub/function_stub.rs index b66223c7d2..5c9d146e18 100644 --- a/compiler/ast/src/stub/function_stub.rs +++ b/compiler/ast/src/stub/function_stub.rs @@ -14,14 +14,35 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{Annotation, CompositeType, External, Function, FunctionInput, FunctionOutput, Identifier, Input, Mode, Node, NodeID, Output, ProgramId, TupleType, Type, Variant, FutureType}; +use crate::{ + Annotation, + CompositeType, + External, + Function, + FunctionInput, + FunctionOutput, + FutureType, + Identifier, + Input, + Mode, + Node, + NodeID, + Output, + ProgramId, + TupleType, + Type, + Variant, +}; use leo_span::{sym, Span, Symbol}; use crate::Type::Composite; use itertools::Itertools; use serde::{Deserialize, Serialize}; use snarkvm::{ - console::program::{RegisterType::{ExternalRecord, Future, Plaintext, Record}, FinalizeType::{Future as FutureFinalizeType, Plaintext as PlaintextFinalizeType}}, + console::program::{ + FinalizeType::{Future as FutureFinalizeType, Plaintext as PlaintextFinalizeType}, + RegisterType::{ExternalRecord, Future, Plaintext, Record}, + }, prelude::{Network, ValueType}, synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait}, }; @@ -246,26 +267,32 @@ impl FunctionStub { is_async: true, variant: Variant::Transition, identifier: Identifier::new(name, Default::default()), - input: function.finalize_logic().unwrap().inputs().iter().enumerate().map(|(index, input)| { - Input::Internal(FunctionInput { - identifier: Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default()), - mode: Mode::Public, - type_: match input.finalize_type() { - PlaintextFinalizeType(val) => Type::from_snarkvm(&val, name), - FutureFinalizeType(_) => Type::Future(Default::default()), - }, - span: Default::default(), - id: Default::default(), + input: function + .finalize_logic() + .unwrap() + .inputs() + .iter() + .enumerate() + .map(|(index, input)| { + Input::Internal(FunctionInput { + identifier: Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default()), + mode: Mode::Public, + type_: match input.finalize_type() { + PlaintextFinalizeType(val) => Type::from_snarkvm(&val, name), + FutureFinalizeType(_) => Type::Future(Default::default()), + }, + span: Default::default(), + id: Default::default(), + }) }) - }).collect_vec(), + .collect_vec(), output: vec![Output::Internal(FunctionOutput { mode: Mode::Public, - type_: Type::Future(FutureType { inputs: None} ), + type_: Type::Future(FutureType { inputs: None }), span: Default::default(), id: 0, - }) - ], - output_type: Type::Future(FutureType { inputs: None}), + })], + output_type: Type::Future(FutureType { inputs: None }), span: Default::default(), id: 0, } diff --git a/compiler/ast/src/stub/mod.rs b/compiler/ast/src/stub/mod.rs index 55f0351c65..0679e3311b 100644 --- a/compiler/ast/src/stub/mod.rs +++ b/compiler/ast/src/stub/mod.rs @@ -16,8 +16,6 @@ //! A stub contains function templates as well as definitions for mappings, structs, records, and constants. -pub mod finalize_stub; -pub use finalize_stub::*; pub mod function_stub; pub use function_stub::*; diff --git a/compiler/ast/src/types/future.rs b/compiler/ast/src/types/future.rs index 5ae7e99c59..f263d708c2 100644 --- a/compiler/ast/src/types/future.rs +++ b/compiler/ast/src/types/future.rs @@ -42,4 +42,4 @@ impl fmt::Display for crate::FutureType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Future<{}>", self.inputs.iter().map(|x| x.to_string()).collect::>().join(",")) } -} \ No newline at end of file +} diff --git a/compiler/ast/src/types/type_.rs b/compiler/ast/src/types/type_.rs index e36901193d..b83c1563b2 100644 --- a/compiler/ast/src/types/type_.rs +++ b/compiler/ast/src/types/type_.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{common, ArrayType, CompositeType, Identifier, IntegerType, MappingType, TupleType, FutureType}; +use crate::{common, ArrayType, CompositeType, FutureType, Identifier, IntegerType, MappingType, TupleType}; use itertools::Itertools; use leo_span::Symbol; @@ -98,9 +98,9 @@ impl Type { } (Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left .inputs() - .iter() - .zip_eq(right.inputs().iter()) - .all(|(left_type, right_type)| left_type.eq_flat(right_type)), + .iter() + .zip_eq(right.inputs().iter()) + .all(|(left_type, right_type)| left_type.eq_flat(right_type)), _ => false, } } diff --git a/compiler/compiler/src/compiler.rs b/compiler/compiler/src/compiler.rs index 55e0440920..8d8b3e451e 100644 --- a/compiler/compiler/src/compiler.rs +++ b/compiler/compiler/src/compiler.rs @@ -149,8 +149,14 @@ impl<'a> Compiler<'a> { /// Runs the type checker pass. pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> { - let (symbol_table, struct_graph, call_graph) = - TypeChecker::do_pass((&self.ast, self.handler, symbol_table, &self.type_table))?; + let (symbol_table, struct_graph, call_graph) = TypeChecker::do_pass(( + &self.ast, + self.handler, + symbol_table, + &self.type_table, + self.compiler_options.build.conditional_block_max_depth, + self.compiler_options.build.disable_conditional_branch_type_checking, + ))?; if self.compiler_options.output.type_checked_symbol_table { self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?; } diff --git a/compiler/compiler/src/options.rs b/compiler/compiler/src/options.rs index 693e85f9cf..a760ae5e0f 100644 --- a/compiler/compiler/src/options.rs +++ b/compiler/compiler/src/options.rs @@ -28,6 +28,10 @@ pub struct CompilerOptions { pub struct BuildOptions { /// Whether to enable dead code elimination. pub dce_enabled: bool, + /// Max depth to type check nested conditionals. + pub conditional_block_max_depth: usize, + /// Whether to disable type checking for nested conditionals. + pub disable_conditional_branch_type_checking: bool, } #[derive(Clone, Default)] diff --git a/errors/src/errors/type_checker/type_checker_warning.rs b/errors/src/errors/type_checker/type_checker_warning.rs new file mode 100644 index 0000000000..472d0052ad --- /dev/null +++ b/errors/src/errors/type_checker/type_checker_warning.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2019-2023 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::create_messages; + +use std::fmt::Display; + +create_messages!( + /// ParserWarning enum that represents all the warnings for the `leo-parser` crate. + TypeCheckerWarning, + code_mask: 2000i32, + code_prefix: "TYC", + + @formatted + some_paths_do_not_await_all_futures { + args: (num_total_paths: impl Display, num_unawaited_paths: impl Display), + msg: format!("Not all paths through the function await all futures. {num_unawaited_paths}/{num_total_paths} paths contain at least one future that is never awaited."), + help: Some("Ex: `f.await()` to await a future. Remove this warning by including the `--disable-conditional-branch-type-checking` flag.".to_string()), + } + + @formatted + some_paths_contain_duplicate_future_awaits { + args: (num_total_paths: impl Display, num_duplicate_await_paths: impl Display), + msg: format!("Some paths through the function contain duplicate future awaits. {num_duplicate_await_paths}/{num_total_paths} paths contain at least one future that is awaited more than once."), + help: Some("Look at the times `.await()` is called, and try to reduce redundancies. Remove this warning by including the `--disable-conditional-branch-type-checking` flag.".to_string()), + } +); diff --git a/leo/cli/commands/build.rs b/leo/cli/commands/build.rs index cb1c505bba..bfca01707b 100644 --- a/leo/cli/commands/build.rs +++ b/leo/cli/commands/build.rs @@ -39,7 +39,11 @@ type CurrentNetwork = Testnet3; impl From for CompilerOptions { fn from(options: BuildOptions) -> Self { let mut out_options = Self { - build: leo_compiler::BuildOptions { dce_enabled: options.enable_dce }, + build: leo_compiler::BuildOptions { + dce_enabled: options.enable_dce, + conditional_block_max_depth: options.conditional_block_max_depth, + disable_conditional_branch_type_checking: options.disable_conditional_branch_type_checking, + }, output: OutputOptions { symbol_table_spans_enabled: options.enable_symbol_table_spans, initial_symbol_table: options.enable_initial_symbol_table_snapshot, diff --git a/leo/cli/commands/mod.rs b/leo/cli/commands/mod.rs index 0c533b896e..7b2bf03517 100644 --- a/leo/cli/commands/mod.rs +++ b/leo/cli/commands/mod.rs @@ -160,4 +160,8 @@ pub struct BuildOptions { pub enable_inlined_ast_snapshot: bool, #[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")] pub enable_dce_ast_snapshot: bool, + #[clap(long, help = "Max depth to type check nested conditionals.", default_value = "10")] + pub conditional_block_max_depth: usize, + #[clap(long, help = "Disable type checking of nested conditional branches in finalize scope.")] + pub disable_conditional_branch_type_checking: bool, }