use crate::{CompilerState, static_analysis::await_checker::AwaitChecker};
use leo_ast::*;
use leo_errors::{StaticAnalyzerError, StaticAnalyzerWarning};
use leo_span::{Span, Symbol};
pub struct StaticAnalyzingVisitor<'a> {
pub state: &'a mut CompilerState,
pub await_checker: AwaitChecker,
pub current_program: Symbol,
pub variant: Option<Variant>,
pub non_async_external_call_seen: bool,
}
impl StaticAnalyzingVisitor<'_> {
pub fn emit_err(&self, err: StaticAnalyzerError) {
self.state.handler.emit_err(err);
}
pub fn emit_warning(&self, warning: StaticAnalyzerWarning) {
self.state.handler.emit_warning(warning.into());
}
pub fn assert_future_await(&mut self, future: &Option<&Expression>, span: Span) {
let future_variable = match future {
Some(Expression::Identifier(name)) => name,
_ => {
return self.emit_err(StaticAnalyzerError::invalid_await_call(span));
}
};
match self.state.type_table.get(&future_variable.id) {
Some(type_) => {
if !matches!(type_, Type::Future(_)) {
self.emit_err(StaticAnalyzerError::expected_future(future_variable.name, future_variable.span()));
}
if self.await_checker.remove(future_variable) {
self.emit_warning(StaticAnalyzerWarning::future_not_awaited_in_order(
future_variable.name,
future_variable.span(),
));
}
}
None => {
self.emit_err(StaticAnalyzerError::expected_future(future_variable.name, future_variable.span()));
}
}
}
pub fn assert_simple_async_transition_call(&mut self, program: Symbol, function_name: Symbol, span: Span) {
let func_symbol = self
.state
.symbol_table
.lookup_function(Location::new(program, function_name))
.expect("Type checking guarantees functions are present.");
if func_symbol.function.variant != Variant::AsyncTransition {
return;
}
let finalizer = func_symbol
.finalizer
.as_ref()
.expect("Typechecking guarantees that all async transitions have an associated `finalize` field.");
let async_function = self
.state
.symbol_table
.lookup_function(finalizer.location)
.expect("Type checking guarantees functions are present.");
if async_function.function.input.iter().any(|input| matches!(input.type_(), Type::Future(..))) {
self.emit_err(StaticAnalyzerError::async_transition_call_with_future_argument(function_name, span));
}
}
}