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 match self.type_table.get(&input.id()) {
62 Some(Type::Future(..)) if is_call => {
63 if !matches!(additional, Await | Return | FunctionArgument | LastTupleLiteral | Definition) {
65 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
66 }
67 }
68 Some(Type::Future(..)) => {
69 if !matches!(additional, Await | Return | FunctionArgument | LastTupleLiteral | TupleAccess) {
71 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
72 }
73 }
74 Some(Type::Tuple(tuple)) if !matches!(tuple.elements().last(), Some(Type::Future(_))) => {}
75 Some(Type::Tuple(..)) if is_call => {
76 if !matches!(additional, Return | Definition) {
78 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
79 }
80 }
81 Some(Type::Tuple(..)) => {
82 if !matches!(additional, Return | TupleAccess) {
84 self.emit_err(StaticAnalyzerError::misplaced_future(input.span()));
85 }
86 }
87 _ => {}
88 }
89
90 match input {
91 Expression::Array(array) => self.visit_array(array, &Position::Misc),
92 Expression::ArrayAccess(access) => self.visit_array_access(access, &Position::Misc),
93 Expression::AssociatedConstant(constant) => self.visit_associated_constant(constant, &Position::Misc),
94 Expression::AssociatedFunction(function) => self.visit_associated_function(function, &Position::Misc),
95 Expression::Binary(binary) => self.visit_binary(binary, &Position::Misc),
96 Expression::Call(call) => self.visit_call(call, &Position::Misc),
97 Expression::Cast(cast) => self.visit_cast(cast, &Position::Misc),
98 Expression::Struct(struct_) => self.visit_struct_init(struct_, &Position::Misc),
99 Expression::Err(err) => self.visit_err(err, &Position::Misc),
100 Expression::Identifier(identifier) => self.visit_identifier(identifier, &Position::Misc),
101 Expression::Literal(literal) => self.visit_literal(literal, &Position::Misc),
102 Expression::Locator(locator) => self.visit_locator(locator, &Position::Misc),
103 Expression::MemberAccess(access) => self.visit_member_access(access, &Position::Misc),
104 Expression::Repeat(repeat) => self.visit_repeat(repeat, &Position::Misc),
105 Expression::Ternary(ternary) => self.visit_ternary(ternary, &Position::Misc),
106 Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
107 Expression::TupleAccess(access) => self.visit_tuple_access(access, &Position::Misc),
108 Expression::Unary(unary) => self.visit_unary(unary, &Position::Misc),
109 Expression::Unit(unit) => self.visit_unit(unit, &Position::Misc),
110 }
111 }
112
113 fn visit_array_access(
114 &mut self,
115 input: &leo_ast::ArrayAccess,
116 _additional: &Self::AdditionalInput,
117 ) -> Self::Output {
118 self.visit_expression(&input.array, &Position::Misc);
119 self.visit_expression(&input.index, &Position::Misc);
120 }
121
122 fn visit_member_access(
123 &mut self,
124 input: &leo_ast::MemberAccess,
125 _additional: &Self::AdditionalInput,
126 ) -> Self::Output {
127 self.visit_expression(&input.inner, &Position::Misc);
128 }
129
130 fn visit_tuple_access(
131 &mut self,
132 input: &leo_ast::TupleAccess,
133 _additional: &Self::AdditionalInput,
134 ) -> Self::Output {
135 self.visit_expression(&input.tuple, &Position::TupleAccess);
136 }
137
138 fn visit_associated_function(
139 &mut self,
140 input: &leo_ast::AssociatedFunctionExpression,
141 _additional: &Self::AdditionalInput,
142 ) -> Self::Output {
143 let core_function = CoreFunction::from_symbols(input.variant.name, input.name.name)
144 .expect("Typechecking guarantees that this function exists.");
145 let position = if core_function == CoreFunction::FutureAwait { Position::Await } else { Position::Misc };
146 input.arguments.iter().for_each(|arg| {
147 self.visit_expression(arg, &position);
148 });
149 }
150
151 fn visit_call(&mut self, input: &leo_ast::CallExpression, _additional: &Self::AdditionalInput) -> Self::Output {
152 input.arguments.iter().for_each(|expr| {
153 self.visit_expression(expr, &Position::FunctionArgument);
154 });
155 Default::default()
156 }
157
158 fn visit_tuple(&mut self, input: &leo_ast::TupleExpression, additional: &Self::AdditionalInput) -> Self::Output {
159 let next_position = match additional {
160 Position::Definition | Position::Return => Position::LastTupleLiteral,
161 _ => Position::Misc,
162 };
163 let mut iter = input.elements.iter().peekable();
164 while let Some(expr) = iter.next() {
165 let position = if iter.peek().is_some() { &Position::Misc } else { &next_position };
166 self.visit_expression(expr, position);
167 }
168 Default::default()
169 }
170
171 fn visit_definition(&mut self, input: &leo_ast::DefinitionStatement) {
173 if let Some(ty) = input.type_.as_ref() {
174 self.visit_type(ty)
175 }
176 self.visit_expression(&input.value, &Position::Definition);
177 }
178
179 fn visit_return(&mut self, input: &leo_ast::ReturnStatement) {
180 self.visit_expression(&input.expression, &Position::Return);
181 }
182}