Add compiler flags for configuring await checker in nested conditionals

This commit is contained in:
evan-schott 2024-02-26 14:29:29 -08:00
parent 5a499937e6
commit cfee45da8f
10 changed files with 111 additions and 28 deletions

View File

@ -14,14 +14,35 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
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 leo_span::{sym, Span, Symbol};
use crate::Type::Composite; use crate::Type::Composite;
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use snarkvm::{ 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}, prelude::{Network, ValueType},
synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait}, synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait},
}; };
@ -246,26 +267,32 @@ impl FunctionStub {
is_async: true, is_async: true,
variant: Variant::Transition, variant: Variant::Transition,
identifier: Identifier::new(name, Default::default()), identifier: Identifier::new(name, Default::default()),
input: function.finalize_logic().unwrap().inputs().iter().enumerate().map(|(index, input)| { input: function
Input::Internal(FunctionInput { .finalize_logic()
identifier: Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default()), .unwrap()
mode: Mode::Public, .inputs()
type_: match input.finalize_type() { .iter()
PlaintextFinalizeType(val) => Type::from_snarkvm(&val, name), .enumerate()
FutureFinalizeType(_) => Type::Future(Default::default()), .map(|(index, input)| {
}, Input::Internal(FunctionInput {
span: Default::default(), identifier: Identifier::new(Symbol::intern(&format!("a{}", index + 1)), Default::default()),
id: 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 { output: vec![Output::Internal(FunctionOutput {
mode: Mode::Public, mode: Mode::Public,
type_: Type::Future(FutureType { inputs: None} ), type_: Type::Future(FutureType { inputs: None }),
span: Default::default(), span: Default::default(),
id: 0, id: 0,
}) })],
], output_type: Type::Future(FutureType { inputs: None }),
output_type: Type::Future(FutureType { inputs: None}),
span: Default::default(), span: Default::default(),
id: 0, id: 0,
} }

View File

@ -16,8 +16,6 @@
//! A stub contains function templates as well as definitions for mappings, structs, records, and constants. //! 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 mod function_stub;
pub use function_stub::*; pub use function_stub::*;

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{common, ArrayType, CompositeType, Identifier, IntegerType, MappingType, TupleType, FutureType}; use crate::{common, ArrayType, CompositeType, FutureType, Identifier, IntegerType, MappingType, TupleType};
use itertools::Itertools; use itertools::Itertools;
use leo_span::Symbol; use leo_span::Symbol;
@ -98,9 +98,9 @@ impl Type {
} }
(Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left (Type::Future(left), Type::Future(right)) if left.inputs.len() == right.inputs.len() => left
.inputs() .inputs()
.iter() .iter()
.zip_eq(right.inputs().iter()) .zip_eq(right.inputs().iter())
.all(|(left_type, right_type)| left_type.eq_flat(right_type)), .all(|(left_type, right_type)| left_type.eq_flat(right_type)),
_ => false, _ => false,
} }
} }

View File

@ -149,8 +149,14 @@ impl<'a> Compiler<'a> {
/// Runs the type checker pass. /// Runs the type checker pass.
pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> { pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> {
let (symbol_table, struct_graph, call_graph) = let (symbol_table, struct_graph, call_graph) = TypeChecker::do_pass((
TypeChecker::do_pass((&self.ast, self.handler, symbol_table, &self.type_table))?; &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 { if self.compiler_options.output.type_checked_symbol_table {
self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?; self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?;
} }

View File

@ -28,6 +28,10 @@ pub struct CompilerOptions {
pub struct BuildOptions { pub struct BuildOptions {
/// Whether to enable dead code elimination. /// Whether to enable dead code elimination.
pub dce_enabled: bool, 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)] #[derive(Clone, Default)]

View File

@ -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 <https://www.gnu.org/licenses/>.
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()),
}
);

View File

@ -39,7 +39,11 @@ type CurrentNetwork = Testnet3;
impl From<BuildOptions> for CompilerOptions { impl From<BuildOptions> for CompilerOptions {
fn from(options: BuildOptions) -> Self { fn from(options: BuildOptions) -> Self {
let mut out_options = 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 { output: OutputOptions {
symbol_table_spans_enabled: options.enable_symbol_table_spans, symbol_table_spans_enabled: options.enable_symbol_table_spans,
initial_symbol_table: options.enable_initial_symbol_table_snapshot, initial_symbol_table: options.enable_initial_symbol_table_snapshot,

View File

@ -160,4 +160,8 @@ pub struct BuildOptions {
pub enable_inlined_ast_snapshot: bool, pub enable_inlined_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")] #[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")]
pub enable_dce_ast_snapshot: bool, 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,
} }