leo_passes/static_analysis/
future_checker.rs1use crate::TypeTable;
18
19use leo_ast::{AstVisitor, CoreFunction, Expression, Function, Node, Type};
20use leo_errors::{Handler, StaticAnalyzerError};
21
22pub fn future_check_function(function: &Function, type_table: &TypeTable, handler: &Handler) {
26 let mut future_checker = FutureChecker { type_table, handler };
27 future_checker.visit_block(&function.block);
28}
29
30#[derive(Clone, Copy, Debug, Default)]
31enum Position {
32 #[default]
33 Misc,
34 Await,
35 TupleAccess,
36 Return,
37 FunctionArgument,
38 LastTupleLiteral,
39 Definition,
40}
41
42struct FutureChecker<'a> {
43 type_table: &'a TypeTable,
44 handler: &'a Handler,
45}
46
47impl FutureChecker<'_> {
48 fn emit_err(&self, err: StaticAnalyzerError) {
49 self.handler.emit_err(err);
50 }
51}
52
53impl AstVisitor for FutureChecker<'_> {
54 type AdditionalInput = Position;
56 type Output = ();
57
58 fn visit_expression(&mut self, input: &Expression, additional: &Self::AdditionalInput) -> Self::Output {
59 use Position::*;
60 let is_call = matches!(input, Expression::Call(..));
61 let is_async_block = matches!(input, Expression::Async(..));
62 match self.type_table.get(&input.id()) {
63 Some(Type::Future(..)) if is_call | is_async_block => {
64 if !matches!(additional, Await | Return | FunctionArgument | LastTupleLiteral | Definition) {
66 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
67 }
68 }
69 Some(Type::Future(..)) => {
70 if !matches!(additional, Await | Return | FunctionArgument | LastTupleLiteral | TupleAccess) {
72 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
73 }
74 }
75 Some(Type::Tuple(tuple)) if !matches!(tuple.elements().last(), Some(Type::Future(_))) => {}
76 Some(Type::Tuple(..)) if is_call => {
77 if !matches!(additional, Return | Definition) {
79 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
80 }
81 }
82 Some(Type::Tuple(..)) => {
83 if !matches!(additional, Return | TupleAccess) {
85 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
86 }
87 }
88 _ => {}
89 }
90
91 match input {
92 Expression::Array(array) => self.visit_array(array, &Position::Misc),
93 Expression::ArrayAccess(access) => self.visit_array_access(access, &Position::Misc),
94 Expression::AssociatedConstant(constant) => self.visit_associated_constant(constant, &Position::Misc),
95 Expression::AssociatedFunction(function) => self.visit_associated_function(function, &Position::Misc),
96 Expression::Async(async_) => self.visit_async(async_, &Position::Misc),
97 Expression::Binary(binary) => self.visit_binary(binary, &Position::Misc),
98 Expression::Call(call) => self.visit_call(call, &Position::Misc),
99 Expression::Cast(cast) => self.visit_cast(cast, &Position::Misc),
100 Expression::Struct(struct_) => self.visit_struct_init(struct_, &Position::Misc),
101 Expression::Err(err) => self.visit_err(err, &Position::Misc),
102 Expression::Path(path) => self.visit_path(path, &Position::Misc),
103 Expression::Literal(literal) => self.visit_literal(literal, &Position::Misc),
104 Expression::Locator(locator) => self.visit_locator(locator, &Position::Misc),
105 Expression::MemberAccess(access) => self.visit_member_access(access, &Position::Misc),
106 Expression::Repeat(repeat) => self.visit_repeat(repeat, &Position::Misc),
107 Expression::Ternary(ternary) => self.visit_ternary(ternary, &Position::Misc),
108 Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
109 Expression::TupleAccess(access) => self.visit_tuple_access(access, &Position::Misc),
110 Expression::Unary(unary) => self.visit_unary(unary, &Position::Misc),
111 Expression::Unit(unit) => self.visit_unit(unit, &Position::Misc),
112 }
113 }
114
115 fn visit_array_access(
116 &mut self,
117 input: &leo_ast::ArrayAccess,
118 _additional: &Self::AdditionalInput,
119 ) -> Self::Output {
120 self.visit_expression(&input.array, &Position::Misc);
121 self.visit_expression(&input.index, &Position::Misc);
122 }
123
124 fn visit_member_access(
125 &mut self,
126 input: &leo_ast::MemberAccess,
127 _additional: &Self::AdditionalInput,
128 ) -> Self::Output {
129 self.visit_expression(&input.inner, &Position::Misc);
130 }
131
132 fn visit_tuple_access(
133 &mut self,
134 input: &leo_ast::TupleAccess,
135 _additional: &Self::AdditionalInput,
136 ) -> Self::Output {
137 self.visit_expression(&input.tuple, &Position::TupleAccess);
138 }
139
140 fn visit_associated_function(
141 &mut self,
142 input: &leo_ast::AssociatedFunctionExpression,
143 _additional: &Self::AdditionalInput,
144 ) -> Self::Output {
145 let core_function = CoreFunction::from_symbols(input.variant.name, input.name.name)
146 .expect("Typechecking guarantees that this function exists.");
147 let position = if core_function == CoreFunction::FutureAwait { Position::Await } else { Position::Misc };
148 input.arguments.iter().for_each(|arg| {
149 self.visit_expression(arg, &position);
150 });
151 }
152
153 fn visit_call(&mut self, input: &leo_ast::CallExpression, _additional: &Self::AdditionalInput) -> Self::Output {
154 input.arguments.iter().for_each(|expr| {
155 self.visit_expression(expr, &Position::FunctionArgument);
156 });
157 Default::default()
158 }
159
160 fn visit_tuple(&mut self, input: &leo_ast::TupleExpression, additional: &Self::AdditionalInput) -> Self::Output {
161 let next_position = match additional {
162 Position::Definition | Position::Return => Position::LastTupleLiteral,
163 _ => Position::Misc,
164 };
165 let mut iter = input.elements.iter().peekable();
166 while let Some(expr) = iter.next() {
167 let position = if iter.peek().is_some() { &Position::Misc } else { &next_position };
168 self.visit_expression(expr, position);
169 }
170 Default::default()
171 }
172
173 fn visit_definition(&mut self, input: &leo_ast::DefinitionStatement) {
175 if let Some(ty) = input.type_.as_ref() {
176 self.visit_type(ty)
177 }
178 self.visit_expression(&input.value, &Position::Definition);
179 }
180
181 fn visit_return(&mut self, input: &leo_ast::ReturnStatement) {
182 self.visit_expression(&input.expression, &Position::Return);
183 }
184}