leo_passes/static_analysis/
future_checker.rs1use crate::TypeTable;
18
19use leo_ast::{CoreFunction, Expression, ExpressionVisitor, Function, Node, StatementVisitor, Type, TypeVisitor};
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 TypeVisitor for FutureChecker<'_> {}
54
55impl ExpressionVisitor for FutureChecker<'_> {
56 type AdditionalInput = Position;
57 type Output = ();
58
59 fn visit_expression(&mut self, input: &Expression, additional: &Self::AdditionalInput) -> Self::Output {
60 use Position::*;
61 let is_call = matches!(input, Expression::Call(..));
62 match self.type_table.get(&input.id()) {
63 Some(Type::Future(..)) if is_call => {
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::Binary(binary) => self.visit_binary(binary, &Position::Misc),
97 Expression::Call(call) => self.visit_call(call, &Position::Misc),
98 Expression::Cast(cast) => self.visit_cast(cast, &Position::Misc),
99 Expression::Struct(struct_) => self.visit_struct_init(struct_, &Position::Misc),
100 Expression::Err(err) => self.visit_err(err, &Position::Misc),
101 Expression::Identifier(identifier) => self.visit_identifier(identifier, &Position::Misc),
102 Expression::Literal(literal) => self.visit_literal(literal, &Position::Misc),
103 Expression::Locator(locator) => self.visit_locator(locator, &Position::Misc),
104 Expression::MemberAccess(access) => self.visit_member_access(access, &Position::Misc),
105 Expression::Repeat(repeat) => self.visit_repeat(repeat, &Position::Misc),
106 Expression::Ternary(ternary) => self.visit_ternary(ternary, &Position::Misc),
107 Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
108 Expression::TupleAccess(access) => self.visit_tuple_access(access, &Position::Misc),
109 Expression::Unary(unary) => self.visit_unary(unary, &Position::Misc),
110 Expression::Unit(unit) => self.visit_unit(unit, &Position::Misc),
111 }
112 }
113
114 fn visit_array_access(
115 &mut self,
116 input: &leo_ast::ArrayAccess,
117 _additional: &Self::AdditionalInput,
118 ) -> Self::Output {
119 self.visit_expression(&input.array, &Position::Misc);
120 self.visit_expression(&input.index, &Position::Misc);
121 }
122
123 fn visit_member_access(
124 &mut self,
125 input: &leo_ast::MemberAccess,
126 _additional: &Self::AdditionalInput,
127 ) -> Self::Output {
128 self.visit_expression(&input.inner, &Position::Misc);
129 }
130
131 fn visit_tuple_access(
132 &mut self,
133 input: &leo_ast::TupleAccess,
134 _additional: &Self::AdditionalInput,
135 ) -> Self::Output {
136 self.visit_expression(&input.tuple, &Position::TupleAccess);
137 }
138
139 fn visit_associated_function(
140 &mut self,
141 input: &leo_ast::AssociatedFunctionExpression,
142 _additional: &Self::AdditionalInput,
143 ) -> Self::Output {
144 let core_function = CoreFunction::from_symbols(input.variant.name, input.name.name)
145 .expect("Typechecking guarantees that this function exists.");
146 let position = if core_function == CoreFunction::FutureAwait { Position::Await } else { Position::Misc };
147 input.arguments.iter().for_each(|arg| {
148 self.visit_expression(arg, &position);
149 });
150 }
151
152 fn visit_call(&mut self, input: &leo_ast::CallExpression, _additional: &Self::AdditionalInput) -> Self::Output {
153 input.arguments.iter().for_each(|expr| {
154 self.visit_expression(expr, &Position::FunctionArgument);
155 });
156 Default::default()
157 }
158
159 fn visit_tuple(&mut self, input: &leo_ast::TupleExpression, additional: &Self::AdditionalInput) -> Self::Output {
160 let next_position = match additional {
161 Position::Definition | Position::Return => Position::LastTupleLiteral,
162 _ => Position::Misc,
163 };
164 let mut iter = input.elements.iter().peekable();
165 while let Some(expr) = iter.next() {
166 let position = if iter.peek().is_some() { &Position::Misc } else { &next_position };
167 self.visit_expression(expr, position);
168 }
169 Default::default()
170 }
171}
172
173impl StatementVisitor for FutureChecker<'_> {
174 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}