mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-22 22:44:47 +03:00
clippy
This commit is contained in:
parent
c01c61c5e4
commit
997b9051fd
@ -44,11 +44,10 @@ use snarkvm::{
|
||||
FinalizeType::{Future as FutureFinalizeType, Plaintext as PlaintextFinalizeType},
|
||||
RegisterType::{ExternalRecord, Future, Plaintext, Record},
|
||||
},
|
||||
prelude::{Network, ValueType},
|
||||
prelude::{FinalizeType, Network, ValueType},
|
||||
synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait},
|
||||
};
|
||||
use std::fmt;
|
||||
use snarkvm::prelude::FinalizeType;
|
||||
|
||||
/// A function stub definition.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@ -187,15 +186,13 @@ impl FunctionStub {
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::ExternalRecord(loc) => {
|
||||
Output::External(External {
|
||||
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
|
||||
program_name: ProgramId::from(loc.program_id()).name,
|
||||
record: Identifier::from(loc.resource()),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
})
|
||||
}
|
||||
ValueType::ExternalRecord(loc) => Output::External(External {
|
||||
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
|
||||
program_name: ProgramId::from(loc.program_id()).name,
|
||||
record: Identifier::from(loc.resource()),
|
||||
span: Default::default(),
|
||||
id: Default::default(),
|
||||
}),
|
||||
ValueType::Future(_) => Output::Internal(FunctionOutput {
|
||||
mode: Mode::Public,
|
||||
type_: Type::Future(FutureType::new(Vec::new())),
|
||||
|
@ -14,14 +14,13 @@
|
||||
// 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::{Type};
|
||||
use crate::Type;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A future type consisting of the type of the inputs.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
|
||||
pub struct FutureType {
|
||||
// Optional type specification of inputs.
|
||||
pub inputs: Vec<Type>,
|
||||
@ -39,7 +38,6 @@ impl FutureType {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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::<Vec<_>>().join(","))
|
||||
|
@ -103,7 +103,11 @@ pub fn get_build_options(test_config: &TestConfig) -> Vec<BuildOptions> {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
None => vec![BuildOptions { dce_enabled: true, conditional_block_max_depth: 10, disable_conditional_branch_type_checking: false }],
|
||||
None => vec![BuildOptions {
|
||||
dce_enabled: true,
|
||||
conditional_block_max_depth: 10,
|
||||
disable_conditional_branch_type_checking: false,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,7 +752,7 @@ impl ParserContext<'_> {
|
||||
}
|
||||
Token::Future => {
|
||||
Expression::Identifier(Identifier { name: sym::Future, span, id: self.node_builder.next_id() })
|
||||
},
|
||||
}
|
||||
t if crate::type_::TYPE_TOKENS.contains(&t) => Expression::Identifier(Identifier {
|
||||
name: t.keyword_to_symbol().unwrap(),
|
||||
span,
|
||||
|
@ -17,7 +17,7 @@
|
||||
use crate::{CallGraph, StructGraph, SymbolTable, TypeTable};
|
||||
|
||||
use leo_ast::{Function, Program, ProgramId};
|
||||
use leo_span::{Symbol};
|
||||
use leo_span::Symbol;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
@ -51,7 +51,7 @@ pub struct CodeGenerator<'a> {
|
||||
/// The program ID of the current program.
|
||||
pub(crate) program_id: Option<ProgramId>,
|
||||
/// A reference to the finalize caller.
|
||||
pub(crate) finalize_caller: Option<Symbol>,
|
||||
pub(crate) finalize_caller: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
|
@ -15,7 +15,32 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::CodeGenerator;
|
||||
use leo_ast::{AccessExpression, ArrayAccess, ArrayExpression, AssociatedConstant, AssociatedFunction, BinaryExpression, BinaryOperation, CallExpression, CastExpression, ErrExpression, Expression, Identifier, Literal, MemberAccess, MethodCall, Node, StructExpression, TernaryExpression, TupleExpression, Type, UnaryExpression, UnaryOperation, UnitExpression, Variant};
|
||||
use leo_ast::{
|
||||
AccessExpression,
|
||||
ArrayAccess,
|
||||
ArrayExpression,
|
||||
AssociatedConstant,
|
||||
AssociatedFunction,
|
||||
BinaryExpression,
|
||||
BinaryOperation,
|
||||
CallExpression,
|
||||
CastExpression,
|
||||
ErrExpression,
|
||||
Expression,
|
||||
Identifier,
|
||||
Literal,
|
||||
MemberAccess,
|
||||
MethodCall,
|
||||
Node,
|
||||
StructExpression,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
Type,
|
||||
UnaryExpression,
|
||||
UnaryOperation,
|
||||
UnitExpression,
|
||||
Variant,
|
||||
};
|
||||
use leo_span::sym;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
@ -465,7 +490,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
}
|
||||
_ => {
|
||||
unreachable!("All core functions should be known at this phase of compilation")
|
||||
},
|
||||
}
|
||||
};
|
||||
// Add the instruction to the list of instructions.
|
||||
instructions.push_str(&instruction);
|
||||
@ -546,7 +571,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
self.next_register += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add a register for async functions to represent the future created.
|
||||
if func.is_async && func.variant == Variant::Standard {
|
||||
let destination_register = format!("r{}", self.next_register);
|
||||
|
@ -16,11 +16,26 @@
|
||||
|
||||
use crate::CodeGenerator;
|
||||
|
||||
use leo_ast::{AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression, ExpressionStatement, IterationStatement, Mode, Output, ReturnStatement, Statement, Type};
|
||||
use leo_ast::{
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionStatement,
|
||||
IterationStatement,
|
||||
Mode,
|
||||
Output,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
Type,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
fn visit_statement(&mut self, input: &'a Statement) -> String {
|
||||
match input {
|
||||
@ -74,7 +89,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
// Get the output type of the function.
|
||||
let output = self.current_function.unwrap().output.iter();
|
||||
// If the operand string is empty, initialize an empty vector.
|
||||
let mut operand_strings = match operand.is_empty() {
|
||||
let operand_strings = match operand.is_empty() {
|
||||
true => vec![],
|
||||
false => operand.split(' ').collect_vec(),
|
||||
};
|
||||
@ -106,7 +121,9 @@ impl<'a> CodeGenerator<'a> {
|
||||
if let Type::Future(_) = output.type_ {
|
||||
future_output = format!(
|
||||
" output {} as {}.aleo/{}.future;\n",
|
||||
operand, self.program_id.unwrap().name, self.current_function.unwrap().identifier,
|
||||
operand,
|
||||
self.program_id.unwrap().name,
|
||||
self.current_function.unwrap().identifier,
|
||||
);
|
||||
String::new()
|
||||
} else {
|
||||
|
@ -15,9 +15,9 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use leo_ast::Identifier;
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
|
||||
use leo_span::Symbol;
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
|
||||
/// A binary search tree to store all paths through nested conditional blocks.
|
||||
pub type ConditionalTreeNode = TreeNode<Symbol>;
|
||||
|
@ -16,7 +16,16 @@
|
||||
|
||||
use crate::Destructurer;
|
||||
|
||||
use leo_ast::{AccessExpression, Expression, ExpressionReconstructor, Identifier, MemberAccess, Statement, TupleAccess, Type};
|
||||
use leo_ast::{
|
||||
AccessExpression,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
MemberAccess,
|
||||
Statement,
|
||||
TupleAccess,
|
||||
Type,
|
||||
};
|
||||
use leo_span::Symbol;
|
||||
|
||||
impl ExpressionReconstructor for Destructurer<'_> {
|
||||
|
@ -16,7 +16,32 @@
|
||||
|
||||
use crate::{RenameTable, StaticSingleAssigner};
|
||||
|
||||
use leo_ast::{AccessExpression, AssertStatement, AssertVariant, AssignStatement, AssociatedFunction, Block, CallExpression, ConditionalStatement, ConsoleStatement, ConstDeclaration, DefinitionStatement, Expression, ExpressionConsumer, ExpressionStatement, Identifier, IterationStatement, MethodCall, Node, ReturnStatement, Statement, StatementConsumer, TernaryExpression, TupleExpression, Type};
|
||||
use leo_ast::{
|
||||
AccessExpression,
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
AssociatedFunction,
|
||||
Block,
|
||||
CallExpression,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
ConstDeclaration,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionConsumer,
|
||||
ExpressionStatement,
|
||||
Identifier,
|
||||
IterationStatement,
|
||||
MethodCall,
|
||||
Node,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementConsumer,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
Type,
|
||||
};
|
||||
use leo_span::Symbol;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_span::sym::function;
|
||||
|
||||
use leo_span::Symbol;
|
||||
|
||||
use crate::{SymbolTable, VariableSymbol, VariableType};
|
||||
|
@ -15,8 +15,8 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ConditionalTreeNode, TreeNode};
|
||||
use indexmap::{IndexSet};
|
||||
use leo_ast::{Identifier};
|
||||
use indexmap::IndexSet;
|
||||
use leo_ast::Identifier;
|
||||
use leo_errors::TypeCheckerError;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
@ -92,15 +92,11 @@ impl AwaitChecker {
|
||||
parent_nodes: Vec<ConditionalTreeNode>,
|
||||
) -> Vec<ConditionalTreeNode> {
|
||||
// Check if a nested conditional statement signaled their existence.
|
||||
if is_finalize && self.enabled {
|
||||
core::mem::replace(&mut self.to_await, parent_nodes)
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
if is_finalize && self.enabled { core::mem::replace(&mut self.to_await, parent_nodes) } else { Vec::new() }
|
||||
}
|
||||
|
||||
/// Exit scope for conditional statement at current depth.
|
||||
pub fn exit_statement_scope(&mut self, is_finalize: bool, then_nodes: Vec<ConditionalTreeNode>) {
|
||||
pub fn exit_statement_scope(&mut self, is_finalize: bool, then_nodes: Vec<ConditionalTreeNode>) {
|
||||
if is_finalize && self.enabled {
|
||||
// Merge together the current set of nodes (from `otherwise` branch) with `then` nodes.
|
||||
self.to_await.extend(then_nodes);
|
||||
|
@ -21,10 +21,13 @@ use leo_errors::{emitter::Handler, TypeCheckerError};
|
||||
use leo_span::{sym, Span, Symbol};
|
||||
|
||||
use itertools::Itertools;
|
||||
use leo_ast::{CoreFunction::FutureAwait, Variant::Standard};
|
||||
use leo_ast::{
|
||||
CoreFunction::FutureAwait,
|
||||
Type::{Future, Tuple},
|
||||
Variant::Standard,
|
||||
};
|
||||
use snarkvm::console::network::{Network, Testnet3};
|
||||
use std::str::FromStr;
|
||||
use leo_ast::Type::{Future, Tuple};
|
||||
|
||||
fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: &Option<Type>) -> Option<Type> {
|
||||
match (t1, t2) {
|
||||
@ -187,7 +190,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
Future(_) => {
|
||||
// Get the fully inferred type.
|
||||
if let Some(Type::Future(inferred_f)) = self.type_table.get(&access.tuple.id()) {
|
||||
if let Some(Type::Future(inferred_f)) = self.type_table.get(&access.tuple.id()) {
|
||||
// Make sure in range.
|
||||
if access.index.value() >= inferred_f.inputs().len() {
|
||||
self.emit_err(TypeCheckerError::invalid_future_access(
|
||||
@ -659,13 +662,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
let mut ret = if func.is_async && func.variant == Standard {
|
||||
if let Some(Type::Future(_)) = expected {
|
||||
Type::Future(FutureType::new(Vec::new()))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.emit_err(TypeCheckerError::return_type_of_finalize_function_is_future(input.span));
|
||||
Type::Unit
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.assert_and_return_type(func.output_type, expected, input.span())
|
||||
};
|
||||
|
||||
@ -686,7 +687,9 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
// Extract information about futures that are being consumed.
|
||||
if func.is_async && func.variant == Standard && matches!(expected.type_(), Type::Future(_)) {
|
||||
match argument {
|
||||
Expression::Identifier(_) | Expression::Call(_) | Expression::Access(AccessExpression::Tuple(_)) => {
|
||||
Expression::Identifier(_)
|
||||
| Expression::Call(_)
|
||||
| Expression::Access(AccessExpression::Tuple(_)) => {
|
||||
match self.scope_state.call_location.clone() {
|
||||
Some(location) => {
|
||||
// Get the external program and function name.
|
||||
@ -701,7 +704,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
self.emit_err(TypeCheckerError::unknown_future_consumed(
|
||||
"unknown",
|
||||
@ -709,8 +712,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
inferred_finalize_inputs.push(ty.unwrap());
|
||||
}
|
||||
});
|
||||
@ -752,20 +754,20 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
let future_type = Type::Future(FutureType::new(
|
||||
// Assumes that external function stubs have been processed.
|
||||
self.finalize_input_types
|
||||
.get(&Location::new(input.program.unwrap(), Symbol::intern(&format!("finalize/{}",ident.name))))
|
||||
.get(&Location::new(
|
||||
input.program.unwrap(),
|
||||
Symbol::intern(&format!("finalize/{}", ident.name)),
|
||||
))
|
||||
.unwrap()
|
||||
.clone(),
|
||||
));
|
||||
ret = match ret.clone() {
|
||||
Tuple(tup) => {
|
||||
Tuple(TupleType::new(tup.elements().iter().map(|t| {
|
||||
if matches!(t, Future(_)) {
|
||||
future_type.clone()
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}).collect::<Vec<Type>>()))
|
||||
}
|
||||
Tuple(tup) => Tuple(TupleType::new(
|
||||
tup.elements()
|
||||
.iter()
|
||||
.map(|t| if matches!(t, Future(_)) { future_type.clone() } else { t.clone() })
|
||||
.collect::<Vec<Type>>(),
|
||||
)),
|
||||
Future(_) => future_type,
|
||||
_ => {
|
||||
self.emit_err(TypeCheckerError::async_transition_invalid_output(input.span));
|
||||
@ -795,8 +797,10 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
)
|
||||
.unwrap();
|
||||
// Create expectation for finalize inputs that will be checked when checking corresponding finalize function signature.
|
||||
self.finalize_input_types
|
||||
.insert(Location::new(self.scope_state.program_name.unwrap(), ident.name), inferred_finalize_inputs.clone());
|
||||
self.finalize_input_types.insert(
|
||||
Location::new(self.scope_state.program_name.unwrap(), ident.name),
|
||||
inferred_finalize_inputs.clone(),
|
||||
);
|
||||
|
||||
// Set scope state flag.
|
||||
self.scope_state.has_called_finalize = true;
|
||||
@ -886,7 +890,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
Some(future) => {
|
||||
self.scope_state.call_location = Some(future.clone());
|
||||
return Some(var.type_.clone());
|
||||
},
|
||||
}
|
||||
None => {
|
||||
self.emit_err(TypeCheckerError::unknown_future_consumed(input.name, input.span));
|
||||
}
|
||||
|
@ -18,11 +18,10 @@ use crate::{DiGraphError, TypeChecker};
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::{TypeCheckerError, TypeCheckerWarning};
|
||||
use leo_span::{sym, Symbol};
|
||||
use leo_span::sym;
|
||||
|
||||
use snarkvm::console::network::{Network, Testnet3};
|
||||
|
||||
|
||||
use leo_ast::{
|
||||
Input::{External, Internal},
|
||||
Type::Future,
|
||||
@ -92,7 +91,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
if input.variant == Variant::Standard && input.is_async {
|
||||
let finalize_input_map = &mut self.finalize_input_types;
|
||||
let mut future_stubs = input.future_locations.clone();
|
||||
let resolved_inputs:Vec<Type> = input
|
||||
let resolved_inputs: Vec<Type> = input
|
||||
.input
|
||||
.iter()
|
||||
.map(|input_mode| {
|
||||
|
@ -24,7 +24,6 @@ use leo_ast::{
|
||||
};
|
||||
use leo_errors::TypeCheckerError;
|
||||
|
||||
|
||||
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_statement(&mut self, input: &'a Statement) {
|
||||
// No statements can follow a return statement.
|
||||
@ -252,7 +251,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
// Insert the variables into the symbol table.
|
||||
match &input.place {
|
||||
Expression::Identifier(identifier) => self.insert_variable(inferred_type.clone(), identifier, input.type_.clone(), 0, identifier.span),
|
||||
Expression::Identifier(identifier) => {
|
||||
self.insert_variable(inferred_type.clone(), identifier, input.type_.clone(), 0, identifier.span)
|
||||
}
|
||||
Expression::Tuple(tuple_expression) => {
|
||||
let tuple_type = match &input.type_ {
|
||||
Type::Tuple(tuple_type) => tuple_type,
|
||||
@ -289,8 +290,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// Expression statements can only be function calls.
|
||||
if !matches!(
|
||||
input.expression,
|
||||
Expression::Call(_) | Expression::Access(AccessExpression::AssociatedFunction(_)) | Expression::Access(AccessExpression::MethodCall(_)))
|
||||
{
|
||||
Expression::Call(_)
|
||||
| Expression::Access(AccessExpression::AssociatedFunction(_))
|
||||
| Expression::Access(AccessExpression::MethodCall(_))
|
||||
) {
|
||||
self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
|
||||
} else {
|
||||
// Check the expression.
|
||||
@ -383,13 +386,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// We can safely unwrap all self.parent instances because
|
||||
// statements should always have some parent block
|
||||
let parent = self.scope_state.function.unwrap();
|
||||
let func = self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_fn_symbol(self.scope_state.program_name.unwrap(), parent)
|
||||
.map(|f| f.clone());
|
||||
let mut return_type = func.clone()
|
||||
.map(|f| f.output_type.clone());
|
||||
let func = self.symbol_table.borrow().lookup_fn_symbol(self.scope_state.program_name.unwrap(), parent).cloned();
|
||||
let mut return_type = func.clone().map(|f| f.output_type.clone());
|
||||
|
||||
// Fully type the expected return value.
|
||||
if self.scope_state.is_async_transition && self.scope_state.has_called_finalize {
|
||||
@ -402,15 +400,13 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// Need to modify return type since the function signature is just default future, but the actual return type is the fully inferred future of the finalize input type.
|
||||
return_type = match return_type {
|
||||
Some(Future(_)) => Some(inferred_future_type),
|
||||
Some(Tuple(tuple)) => {
|
||||
Some(Tuple(TupleType::new(tuple.elements().iter().map(|t| {
|
||||
if matches!(t, Future(_)) {
|
||||
inferred_future_type.clone()
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}).collect::<Vec<Type>>())))
|
||||
}
|
||||
Some(Tuple(tuple)) => Some(Tuple(TupleType::new(
|
||||
tuple
|
||||
.elements()
|
||||
.iter()
|
||||
.map(|t| if matches!(t, Future(_)) { inferred_future_type.clone() } else { t.clone() })
|
||||
.collect::<Vec<Type>>(),
|
||||
))),
|
||||
_ => {
|
||||
return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
|
||||
}
|
||||
|
@ -39,12 +39,14 @@ use leo_span::{Span, Symbol};
|
||||
use snarkvm::console::network::{Network, Testnet3};
|
||||
|
||||
use crate::type_checking::{await_checker::AwaitChecker, scope_state::ScopeState};
|
||||
use indexmap::{IndexMap};
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use leo_ast::Type::{Future, Tuple};
|
||||
use std::{cell::RefCell};
|
||||
use leo_ast::Input::Internal;
|
||||
use leo_ast::Mode::Public;
|
||||
use leo_ast::{
|
||||
Input::Internal,
|
||||
Mode::Public,
|
||||
Type::{Future, Tuple},
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct TypeChecker<'a> {
|
||||
/// The symbol table for the program.
|
||||
@ -1251,7 +1253,7 @@ impl<'a> TypeChecker<'a> {
|
||||
if !function.output.is_empty() {
|
||||
self.emit_err(TypeCheckerError::finalize_function_cannot_return_value(function.span()));
|
||||
}
|
||||
|
||||
|
||||
// Check that the input types are consistent with when the function is invoked.
|
||||
if let Some(inferred_input_types) = self.finalize_input_types.get(&self.scope_state.location()) {
|
||||
// Check same number of inputs as expected.
|
||||
@ -1263,30 +1265,26 @@ impl<'a> TypeChecker<'a> {
|
||||
));
|
||||
}
|
||||
// Check that the input parameters match the inferred types from when the async function is invoked.
|
||||
function
|
||||
.input
|
||||
.iter()
|
||||
.zip_eq(inferred_input_types.iter())
|
||||
.for_each(|(t1, t2)| {
|
||||
if let Internal(fn_input) = t1 {
|
||||
// Allow partial type matching of futures since inferred are fully typed, whereas AST has default futures.
|
||||
if !(matches!(t2, Type::Future(_)) && matches!(fn_input.type_, Type::Future(_))) {
|
||||
self.check_eq_types(&Some(t1.type_()), &Some(t2.clone()), t1.span())
|
||||
} else {
|
||||
// Insert to symbol table
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
fn_input.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: t2.clone(),
|
||||
span: fn_input.identifier.span(),
|
||||
declaration: VariableType::Input(Public),
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
function.input.iter().zip_eq(inferred_input_types.iter()).for_each(|(t1, t2)| {
|
||||
if let Internal(fn_input) = t1 {
|
||||
// Allow partial type matching of futures since inferred are fully typed, whereas AST has default futures.
|
||||
if !(matches!(t2, Type::Future(_)) && matches!(fn_input.type_, Type::Future(_))) {
|
||||
self.check_eq_types(&Some(t1.type_()), &Some(t2.clone()), t1.span())
|
||||
} else {
|
||||
// Insert to symbol table
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
fn_input.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: t2.clone(),
|
||||
span: fn_input.identifier.span(),
|
||||
declaration: VariableType::Input(Public),
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
|
||||
function.identifier.name,
|
||||
@ -1319,7 +1317,10 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
|
||||
// Check that the finalize input parameter is not constant or private.
|
||||
if self.scope_state.is_finalize && (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private) && (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private) {
|
||||
if self.scope_state.is_finalize
|
||||
&& (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private)
|
||||
&& (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private)
|
||||
{
|
||||
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
|
||||
}
|
||||
|
||||
@ -1338,11 +1339,13 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
// Add function inputs to the symbol table. Futures have already been added.
|
||||
if !matches!(&input_var.type_(), &Type::Future(_)) {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
}) {
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
})
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
@ -1390,7 +1393,8 @@ impl<'a> TypeChecker<'a> {
|
||||
// Async transitions must return exactly one future, and it must be in the last position.
|
||||
if self.scope_state.is_async_transition
|
||||
&& ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
|
||||
|| (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
|
||||
|| (index == function.output.len() - 1
|
||||
&& !matches!(function_output.type_, Type::Future(_))))
|
||||
{
|
||||
self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use leo_ast::{Identifier, Location, Variant};
|
||||
use leo_ast::{Location, Variant};
|
||||
use leo_span::Symbol;
|
||||
|
||||
pub struct ScopeState {
|
||||
|
@ -923,14 +923,14 @@ create_messages!(
|
||||
msg: "An async transition must return a future.".to_string(),
|
||||
help: Some("Call an async function inside of the async transition body so that there is a future to return.".to_string()),
|
||||
}
|
||||
|
||||
|
||||
@formatted
|
||||
finalize_function_cannot_return_value {
|
||||
args: (),
|
||||
msg: "An async function is not allowed to return a value.".to_string(),
|
||||
help: Some("Remove an output type in the function signature, and remove the return statement from the function.".to_string()),
|
||||
}
|
||||
|
||||
|
||||
@formatted
|
||||
return_type_of_finalize_function_is_future {
|
||||
args: (),
|
||||
|
@ -37,7 +37,7 @@ create_messages!(
|
||||
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()),
|
||||
}
|
||||
|
||||
|
||||
@formatted
|
||||
async_function_is_never_called_by_transition_function {
|
||||
args: (name: impl Display),
|
||||
|
@ -89,7 +89,11 @@ fn new_compiler(handler: &Handler) -> Compiler<'_> {
|
||||
PathBuf::from(String::new()),
|
||||
PathBuf::from(String::new()),
|
||||
Some(CompilerOptions {
|
||||
build: BuildOptions { dce_enabled: true, conditional_block_max_depth: 10, disable_conditional_branch_type_checking: false },
|
||||
build: BuildOptions {
|
||||
dce_enabled: true,
|
||||
conditional_block_max_depth: 10,
|
||||
disable_conditional_branch_type_checking: false,
|
||||
},
|
||||
output: OutputOptions {
|
||||
symbol_table_spans_enabled: false,
|
||||
initial_symbol_table: false,
|
||||
|
Loading…
Reference in New Issue
Block a user