leo_passes/static_analysis/
visitor.rs1use crate::{CompilerState, static_analysis::await_checker::AwaitChecker};
18
19use leo_ast::*;
20use leo_errors::{StaticAnalyzerError, StaticAnalyzerWarning};
21use leo_span::{Span, Symbol};
22
23pub struct StaticAnalyzingVisitor<'a> {
24 pub state: &'a mut CompilerState,
25 pub await_checker: AwaitChecker,
27 pub current_program: Symbol,
29 pub variant: Option<Variant>,
31 pub non_async_external_call_seen: bool,
33}
34
35impl StaticAnalyzingVisitor<'_> {
36 pub fn emit_err(&self, err: StaticAnalyzerError) {
37 self.state.handler.emit_err(err);
38 }
39
40 pub fn emit_warning(&self, warning: StaticAnalyzerWarning) {
42 self.state.handler.emit_warning(warning.into());
43 }
44
45 pub fn assert_future_await(&mut self, future: &Option<&Expression>, span: Span) {
47 let future_variable = match future {
49 Some(Expression::Identifier(name)) => name,
50 _ => {
51 return self.emit_err(StaticAnalyzerError::invalid_await_call(span));
52 }
53 };
54
55 match self.state.type_table.get(&future_variable.id) {
57 Some(type_) => {
58 if !matches!(type_, Type::Future(_)) {
59 self.emit_err(StaticAnalyzerError::expected_future(future_variable.name, future_variable.span()));
60 }
61 if self.await_checker.remove(future_variable) {
64 self.emit_warning(StaticAnalyzerWarning::future_not_awaited_in_order(
65 future_variable.name,
66 future_variable.span(),
67 ));
68 }
69 }
70 None => {
71 self.emit_err(StaticAnalyzerError::expected_future(future_variable.name, future_variable.span()));
72 }
73 }
74 }
75
76 pub fn assert_simple_async_transition_call(&mut self, program: Symbol, function_name: Symbol, span: Span) {
79 let func_symbol = self
80 .state
81 .symbol_table
82 .lookup_function(Location::new(program, function_name))
83 .expect("Type checking guarantees functions are present.");
84
85 if func_symbol.function.variant != Variant::AsyncTransition {
87 return;
88 }
89
90 let finalizer = func_symbol
91 .finalizer
92 .as_ref()
93 .expect("Typechecking guarantees that all async transitions have an associated `finalize` field.");
94
95 let async_function = self
96 .state
97 .symbol_table
98 .lookup_function(finalizer.location)
99 .expect("Type checking guarantees functions are present.");
100
101 if async_function.function.input.iter().any(|input| matches!(input.type_(), Type::Future(..))) {
103 self.emit_err(StaticAnalyzerError::async_transition_call_with_future_argument(function_name, span));
104 }
105 }
106}
107
108impl TypeVisitor for StaticAnalyzingVisitor<'_> {}