leo_passes/type_checking/
ast.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18use crate::{VariableSymbol, VariableType};
19
20use leo_ast::{
21    Type::{Future, Tuple},
22    *,
23};
24use leo_errors::{TypeCheckerError, TypeCheckerWarning};
25use leo_span::{Span, Symbol, sym};
26
27use itertools::Itertools as _;
28
29impl TypeCheckingVisitor<'_> {
30    // Returns the type of the RHS of an assign statement. Also returns whether the RHS is a storage location.
31    // For now, the only possible storage location to assign to is a `Path` to a storage variable name.
32    pub fn visit_expression_assign(&mut self, input: &Expression) -> (Type, bool) {
33        let (ty, is_storage) = match input {
34            Expression::ArrayAccess(array_access) => {
35                (self.visit_array_access_general(array_access, true, &None), false)
36            }
37            Expression::Path(path) if path.qualifier().is_empty() => self.visit_path_assign(path),
38            Expression::MemberAccess(member_access) => {
39                (self.visit_member_access_general(member_access, true, &None), false)
40            }
41            Expression::TupleAccess(tuple_access) => {
42                (self.visit_tuple_access_general(tuple_access, true, &None), false)
43            }
44            _ => {
45                self.emit_err(TypeCheckerError::invalid_assignment_target(input, input.span()));
46                (Type::Err, false)
47            }
48        };
49
50        // Prohibit assignment to an external record in a narrower conditional scope.
51        let external_record = self.is_external_record(&ty);
52        let external_record_tuple =
53            matches!(&ty, Type::Tuple(tuple) if tuple.elements().iter().any(|ty| self.is_external_record(ty)));
54
55        if external_record || external_record_tuple {
56            let Expression::Path(path) = input else {
57                // This is not valid Leo and will have triggered an error elsewhere.
58                return (Type::Err, false);
59            };
60
61            if !self.symbol_in_conditional_scope(path.identifier().name) {
62                if external_record {
63                    self.emit_err(TypeCheckerError::assignment_to_external_record_cond(&ty, input.span()));
64                } else {
65                    // Note that this will cover both assigning to a tuple variable and assigning to a member of a tuple.
66                    self.emit_err(TypeCheckerError::assignment_to_external_record_tuple_cond(&ty, input.span()));
67                }
68            }
69        }
70
71        // Prohibit reassignment of futures.
72        if let Type::Future(..) = ty {
73            self.emit_err(TypeCheckerError::cannot_reassign_future_variable(input, input.span()));
74        }
75
76        // Prohibit reassignment of mappings.
77        if let Type::Mapping(_) = ty {
78            self.emit_err(TypeCheckerError::cannot_reassign_mapping(input, input.span()));
79        }
80
81        // Add the expression and its associated type to the type table.
82        self.state.type_table.insert(input.id(), ty.clone());
83
84        (ty, is_storage)
85    }
86
87    pub fn visit_array_access_general(&mut self, input: &ArrayAccess, assign: bool, expected: &Option<Type>) -> Type {
88        // Check that the expression is an array.
89        let this_type = if assign {
90            self.visit_expression_assign(&input.array).0
91        } else {
92            self.visit_expression(&input.array, &None)
93        };
94        self.assert_array_type(&this_type, input.array.span());
95
96        // Check that the index is an integer type.
97        let mut index_type = self.visit_expression(&input.index, &None);
98
99        if index_type == Type::Numeric {
100            // If the index has type `Numeric`, then it's an unsuffixed literal. Just infer its type to be `u32` and
101            // then check it's validity as a `u32`.
102            index_type = Type::Integer(IntegerType::U32);
103            if let Expression::Literal(literal) = &input.index {
104                self.check_numeric_literal(literal, &index_type);
105            }
106        }
107
108        self.assert_int_type(&index_type, input.index.span());
109
110        // Keep track of the type of the index in the type table.
111        // This is important for when the index is an unsuffixed literal.
112        self.state.type_table.insert(input.index.id(), index_type.clone());
113
114        // Get the element type of the array.
115        let Type::Array(array_type) = this_type else {
116            // We must have already reported an error above, in our type assertion.
117            return Type::Err;
118        };
119
120        let element_type = array_type.element_type();
121
122        // If the expected type is known, then check that the element type is the same as the expected type.
123        self.maybe_assert_type(element_type, expected, input.span());
124
125        // Return the element type of the array.
126        element_type.clone()
127    }
128
129    pub fn visit_member_access_general(&mut self, input: &MemberAccess, assign: bool, expected: &Option<Type>) -> Type {
130        // Handler member access expressions that correspond to valid operands in AVM code.
131        if !assign {
132            match &input.inner {
133                // If the access expression is of the form `self.<name>`, then check the <name> is valid.
134                Expression::Path(path) if path.identifier().name == sym::SelfLower => {
135                    match input.name.name {
136                        sym::address => {
137                            let ty = Type::Address;
138                            self.maybe_assert_type(&ty, expected, input.span());
139                            return ty;
140                        }
141                        sym::caller => {
142                            // Check that the operation is not invoked in a `finalize` block.
143                            self.check_access_allowed("self.caller", false, input.name.span());
144
145                            let ty = Type::Address;
146                            self.maybe_assert_type(&ty, expected, input.span());
147                            return ty;
148                        }
149                        sym::checksum => {
150                            let ty = Type::Array(ArrayType::new(
151                                Type::Integer(IntegerType::U8),
152                                Expression::Literal(Literal::integer(
153                                    IntegerType::U8,
154                                    "32".to_string(),
155                                    Default::default(),
156                                    Default::default(),
157                                )),
158                            ));
159                            self.maybe_assert_type(&ty, expected, input.span());
160                            return ty;
161                        }
162                        sym::edition => {
163                            let ty = Type::Integer(IntegerType::U16);
164                            self.maybe_assert_type(&ty, expected, input.span());
165                            return ty;
166                        }
167                        sym::id => {
168                            let ty = Type::Address;
169                            self.maybe_assert_type(&ty, expected, input.span());
170                            return ty;
171                        }
172                        sym::program_owner => {
173                            // Check that the operation is only invoked in a `finalize` block.
174                            self.check_access_allowed("self.program_owner", true, input.name.span());
175
176                            let ty = Type::Address;
177                            self.maybe_assert_type(&ty, expected, input.span());
178                            return ty;
179                        }
180                        sym::signer => {
181                            // Check that operation is not invoked in a `finalize` block.
182                            self.check_access_allowed("self.signer", false, input.name.span());
183
184                            let ty = Type::Address;
185                            self.maybe_assert_type(&ty, expected, input.span());
186                            return ty;
187                        }
188                        _ => {
189                            self.emit_err(TypeCheckerError::invalid_self_access(input.name.span()));
190                            return Type::Err;
191                        }
192                    }
193                }
194                // If the access expression is of the form `block.<name>`, then check the <name> is valid.
195                Expression::Path(path) if path.identifier().name == sym::block => match input.name.name {
196                    sym::height => {
197                        // Check that the operation is invoked in a `finalize` block.
198                        self.check_access_allowed("block.height", true, input.name.span());
199                        let ty = Type::Integer(IntegerType::U32);
200                        self.maybe_assert_type(&ty, expected, input.span());
201                        return ty;
202                    }
203                    sym::timestamp => {
204                        // Check that the operation is invoked in a `finalize` block.
205                        self.check_access_allowed("block.timestamp", true, input.name.span());
206                        let ty = Type::Integer(IntegerType::I64);
207                        self.maybe_assert_type(&ty, expected, input.span());
208                        return ty;
209                    }
210                    _ => {
211                        self.emit_err(TypeCheckerError::invalid_block_access(input.name.span()));
212                        return Type::Err;
213                    }
214                },
215                // If the access expression is of the form `network.<name>`, then check that the <name> is valid.
216                Expression::Path(path) if path.identifier().name == sym::network => match input.name.name {
217                    sym::id => {
218                        // Check that the operation is not invoked outside a `finalize` block.
219                        self.check_access_allowed("network.id", true, input.name.span());
220                        let ty = Type::Integer(IntegerType::U16);
221                        self.maybe_assert_type(&ty, expected, input.span());
222                        return ty;
223                    }
224                    _ => {
225                        self.emit_err(TypeCheckerError::invalid_block_access(input.name.span()));
226                        return Type::Err;
227                    }
228                },
229                _ => {}
230            }
231        }
232
233        let ty = if assign {
234            self.visit_expression_assign(&input.inner).0
235        } else {
236            self.visit_expression(&input.inner, &None)
237        };
238
239        // Make sure we're not assigning to a member of an external record.
240        if assign && self.is_external_record(&ty) {
241            self.emit_err(TypeCheckerError::assignment_to_external_record_member(&ty, input.span));
242        }
243
244        // Check that the type of `inner` in `inner.name` is a struct.
245        match ty {
246            Type::Err => Type::Err,
247            Type::Composite(ref struct_) => {
248                // Retrieve the struct definition associated with `identifier`.
249                let Some(struct_) = self
250                    .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
251                else {
252                    self.emit_err(TypeCheckerError::undefined_type(ty, input.inner.span()));
253                    return Type::Err;
254                };
255                // Check that `input.name` is a member of the struct.
256                match struct_.members.iter().find(|member| member.name() == input.name.name) {
257                    // Case where `input.name` is a member of the struct.
258                    Some(Member { type_, .. }) => {
259                        // Check that the type of `input.name` is the same as `expected`.
260                        self.maybe_assert_type(type_, expected, input.span());
261                        type_.clone()
262                    }
263                    // Case where `input.name` is not a member of the struct.
264                    None => {
265                        self.emit_err(TypeCheckerError::invalid_struct_variable(
266                            input.name,
267                            &struct_,
268                            input.name.span(),
269                        ));
270                        Type::Err
271                    }
272                }
273            }
274            type_ => {
275                self.emit_err(TypeCheckerError::type_should_be2(type_, "a struct or record", input.inner.span()));
276                Type::Err
277            }
278        }
279    }
280
281    pub fn visit_tuple_access_general(&mut self, input: &TupleAccess, assign: bool, expected: &Option<Type>) -> Type {
282        let this_type = if assign {
283            self.visit_expression_assign(&input.tuple).0
284        } else {
285            self.visit_expression(&input.tuple, &None)
286        };
287        match this_type {
288            Type::Err => Type::Err,
289            Type::Tuple(tuple) => {
290                // Check out of range input.
291                let index = input.index.value();
292                let Some(actual) = tuple.elements().get(index) else {
293                    self.emit_err(TypeCheckerError::tuple_out_of_range(index, tuple.length(), input.span()));
294                    return Type::Err;
295                };
296
297                self.maybe_assert_type(actual, expected, input.span());
298
299                actual.clone()
300            }
301            Type::Future(_) => {
302                // Get the fully inferred type.
303                let Some(Type::Future(inferred_f)) = self.state.type_table.get(&input.tuple.id()) else {
304                    // If a future type was not inferred, we will have already reported an error.
305                    return Type::Err;
306                };
307
308                if inferred_f.location.is_none() {
309                    // This generally means that the `Future` is produced by an `async` block expression and not an
310                    // `async function` function call.
311                    self.emit_err(TypeCheckerError::invalid_async_block_future_access(input.span()));
312                    return Type::Err;
313                }
314
315                let Some(actual) = inferred_f.inputs().get(input.index.value()) else {
316                    self.emit_err(TypeCheckerError::invalid_future_access(
317                        input.index.value(),
318                        inferred_f.inputs().len(),
319                        input.span(),
320                    ));
321                    return Type::Err;
322                };
323
324                // If all inferred types weren't the same, the member will be of type `Type::Err`.
325                if let Type::Err = actual {
326                    self.emit_err(TypeCheckerError::future_error_member(input.index.value(), input.span()));
327                    return Type::Err;
328                }
329
330                self.maybe_assert_type(actual, expected, input.span());
331
332                actual.clone()
333            }
334            type_ => {
335                self.emit_err(TypeCheckerError::type_should_be2(type_, "a tuple or future", input.span()));
336                Type::Err
337            }
338        }
339    }
340
341    // Returns the type of the RHS of an assign statement if it's a `Path`.
342    // Also returns whether the RHS is a storage location.
343    pub fn visit_path_assign(&mut self, input: &Path) -> (Type, bool) {
344        // Lookup the variable in the symbol table and retrieve its type.
345        let Some(var) =
346            self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path())
347        else {
348            self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span));
349            return (Type::Err, false);
350        };
351
352        // Cannot assign to storage vectors
353        if var.type_.is_vector() {
354            self.emit_err(TypeCheckerError::invalid_assignment_target(input, input.span()));
355            return (Type::Err, false);
356        }
357
358        // If the variable exists, then check that it is not a constant.
359        match &var.declaration {
360            VariableType::Const => self.emit_err(TypeCheckerError::cannot_assign_to_const_var(input, var.span)),
361            VariableType::ConstParameter => {
362                self.emit_err(TypeCheckerError::cannot_assign_to_generic_const_function_parameter(input, input.span))
363            }
364            VariableType::Input(Mode::Constant) => {
365                self.emit_err(TypeCheckerError::cannot_assign_to_const_input(input, var.span))
366            }
367            VariableType::Storage => return (var.type_.clone(), true),
368            VariableType::Mut | VariableType::Input(_) => {}
369        }
370
371        // If the variable exists and it's in an async function, then check that it is in the current conditional scope.
372        if self.scope_state.variant.unwrap().is_async_function()
373            && !self.symbol_in_conditional_scope(input.identifier().name)
374        {
375            self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "function", var.span));
376        }
377
378        // Similarly, if the variable exists and it's in an async block, then check that it is in the current conditional scope.
379        if self.async_block_id.is_some() && !self.symbol_in_conditional_scope(input.identifier().name) {
380            self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "block", var.span));
381        }
382
383        if let Some(async_block_id) = self.async_block_id
384            && !self.state.symbol_table.is_defined_in_scope_or_ancestor_until(async_block_id, input.identifier().name)
385        {
386            // If we're inside an async block (i.e. in the scope of its block or one if its child scopes) and if
387            // we're trying to assign to a variable that is not local to the block (or its child scopes), then we
388            // should error out.
389            self.emit_err(TypeCheckerError::cannot_assign_to_vars_outside_async_block(
390                input.identifier().name,
391                input.span,
392            ));
393        }
394
395        (var.type_.clone(), false)
396    }
397
398    /// Infers the type of an expression, but returns Type::Err and emits an error if the result is Type::Numeric.
399    /// Used to disallow numeric types in specific contexts where they are not valid or expected.
400    pub(crate) fn visit_expression_reject_numeric(&mut self, expr: &Expression, expected: &Option<Type>) -> Type {
401        let mut inferred = self.visit_expression(expr, expected);
402        match inferred {
403            Type::Numeric => {
404                self.emit_inference_failure_error(&mut inferred, expr);
405                Type::Err
406            }
407            _ => inferred,
408        }
409    }
410
411    /// Infers the type of an expression, and if it is `Type::Numeric`, coerces it to `U32`, validates it, and
412    /// records it in the type table.
413    pub(crate) fn visit_expression_infer_default_u32(&mut self, expr: &Expression) -> Type {
414        let mut inferred = self.visit_expression(expr, &None);
415
416        if inferred == Type::Numeric {
417            inferred = Type::Integer(IntegerType::U32);
418
419            if let Expression::Literal(literal) = expr
420                && !self.check_numeric_literal(literal, &inferred)
421            {
422                inferred = Type::Err;
423            }
424
425            self.state.type_table.insert(expr.id(), inferred.clone());
426        }
427
428        inferred
429    }
430}
431
432impl AstVisitor for TypeCheckingVisitor<'_> {
433    type AdditionalInput = Option<Type>;
434    type Output = Type;
435
436    /* Types */
437    fn visit_array_type(&mut self, input: &ArrayType) {
438        self.visit_type(&input.element_type);
439        self.visit_expression_infer_default_u32(&input.length);
440    }
441
442    fn visit_composite_type(&mut self, input: &CompositeType) {
443        let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
444
445        if let Some(struct_) = struct_ {
446            // Check the number of const arguments against the number of the struct's const parameters
447            if struct_.const_parameters.len() != input.const_arguments.len() {
448                self.emit_err(TypeCheckerError::incorrect_num_const_args(
449                    "Struct type",
450                    struct_.const_parameters.len(),
451                    input.const_arguments.len(),
452                    input.path.span,
453                ));
454            }
455
456            // Check the types of const arguments against the types of the struct's const parameters
457            for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
458                self.visit_expression(argument, &Some(expected.type_().clone()));
459            }
460        } else if !input.const_arguments.is_empty() {
461            self.emit_err(TypeCheckerError::unexpected_const_args(input, input.path.span));
462        }
463    }
464
465    /* Expressions */
466    fn visit_expression(&mut self, input: &Expression, additional: &Self::AdditionalInput) -> Self::Output {
467        let output = match input {
468            Expression::Array(array) => self.visit_array(array, additional),
469            Expression::ArrayAccess(access) => self.visit_array_access_general(access, false, additional),
470            Expression::AssociatedConstant(constant) => self.visit_associated_constant(constant, additional),
471            Expression::AssociatedFunction(function) => self.visit_associated_function(function, additional),
472            Expression::Async(async_) => self.visit_async(async_, additional),
473            Expression::Binary(binary) => self.visit_binary(binary, additional),
474            Expression::Call(call) => self.visit_call(call, additional),
475            Expression::Cast(cast) => self.visit_cast(cast, additional),
476            Expression::Struct(struct_) => self.visit_struct_init(struct_, additional),
477            Expression::Err(err) => self.visit_err(err, additional),
478            Expression::Path(path) => self.visit_path(path, additional),
479            Expression::Literal(literal) => self.visit_literal(literal, additional),
480            Expression::Locator(locator) => self.visit_locator(locator, additional),
481            Expression::MemberAccess(access) => self.visit_member_access_general(access, false, additional),
482            Expression::Repeat(repeat) => self.visit_repeat(repeat, additional),
483            Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
484            Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
485            Expression::TupleAccess(access) => self.visit_tuple_access_general(access, false, additional),
486            Expression::Unary(unary) => self.visit_unary(unary, additional),
487            Expression::Unit(unit) => self.visit_unit(unit, additional),
488        };
489
490        // Add the expression and its associated type to the symbol table.
491        self.state.type_table.insert(input.id(), output.clone());
492        output
493    }
494
495    fn visit_array_access(&mut self, _input: &ArrayAccess, _additional: &Self::AdditionalInput) -> Self::Output {
496        panic!("Should not be called.");
497    }
498
499    fn visit_member_access(&mut self, _input: &MemberAccess, _additional: &Self::AdditionalInput) -> Self::Output {
500        panic!("Should not be called.");
501    }
502
503    fn visit_tuple_access(&mut self, _input: &TupleAccess, _additional: &Self::AdditionalInput) -> Self::Output {
504        panic!("Should not be called.");
505    }
506
507    fn visit_array(&mut self, input: &ArrayExpression, additional: &Self::AdditionalInput) -> Self::Output {
508        // Grab the element type from the expected type if the expected type is an array or if it's
509        // an optional array
510        let element_type = match additional {
511            Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
512            Some(Type::Optional(opt)) => match &*opt.inner {
513                Type::Array(array_ty) => Some(array_ty.element_type().clone()),
514                _ => None,
515            },
516            _ => None,
517        };
518
519        let inferred_type = if input.elements.is_empty() {
520            if let Some(ty) = element_type.clone() {
521                ty
522            } else {
523                self.emit_err(TypeCheckerError::could_not_determine_type(input, input.span()));
524                Type::Err
525            }
526        } else {
527            self.visit_expression_reject_numeric(&input.elements[0], &element_type)
528        };
529
530        if input.elements.len() > self.limits.max_array_elements {
531            self.emit_err(TypeCheckerError::array_too_large(
532                input.elements.len(),
533                self.limits.max_array_elements,
534                input.span(),
535            ));
536        }
537
538        for expression in input.elements.iter().skip(1) {
539            let next_type = self.visit_expression_reject_numeric(expression, &element_type);
540
541            if next_type == Type::Err {
542                return Type::Err;
543            }
544
545            if let Some(ref element_type) = element_type {
546                self.assert_type(&next_type, element_type, expression.span());
547            } else {
548                self.assert_type(&next_type, &inferred_type, expression.span());
549            }
550        }
551
552        if inferred_type == Type::Err {
553            return Type::Err;
554        }
555
556        let type_ = Type::Array(ArrayType::new(
557            inferred_type,
558            Expression::Literal(Literal {
559                // The default type for array length is `U32`.
560                variant: LiteralVariant::Integer(IntegerType::U32, input.elements.len().to_string()),
561                id: self.state.node_builder.next_id(),
562                span: Span::default(),
563            }),
564        ));
565
566        self.maybe_assert_type(&type_, additional, input.span());
567
568        type_
569    }
570
571    fn visit_repeat(&mut self, input: &RepeatExpression, additional: &Self::AdditionalInput) -> Self::Output {
572        // Grab the element type from the expected type if the expected type is an array or if it's
573        // an optional array
574        let expected_element_type = match additional {
575            Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
576            Some(Type::Optional(opt)) => match &*opt.inner {
577                Type::Array(array_ty) => Some(array_ty.element_type().clone()),
578                _ => None,
579            },
580            _ => None,
581        };
582
583        let inferred_element_type = self.visit_expression_reject_numeric(&input.expr, &expected_element_type);
584
585        // Now infer the type of `count`. If it's an unsuffixed literal (i.e. has `Type::Numeric`), then infer it to be
586        // a `U32` as the default type.
587        self.visit_expression_infer_default_u32(&input.count);
588
589        // If we can already evaluate the repeat count as a `u32`, then make sure it's not 0 or  greater than the array
590        // size limit.
591        if let Some(count) = input.count.as_u32()
592            && count > self.limits.max_array_elements as u32
593        {
594            self.emit_err(TypeCheckerError::array_too_large(count, self.limits.max_array_elements, input.span()));
595        }
596
597        let type_ = Type::Array(ArrayType::new(inferred_element_type, input.count.clone()));
598
599        self.maybe_assert_type(&type_, additional, input.span());
600        type_
601    }
602
603    fn visit_associated_constant(
604        &mut self,
605        input: &AssociatedConstantExpression,
606        expected: &Self::AdditionalInput,
607    ) -> Self::Output {
608        // Check associated constant type and constant name
609        let Some(core_constant) = self.get_core_constant(&input.ty, &input.name) else {
610            self.emit_err(TypeCheckerError::invalid_associated_constant(input, input.span));
611            return Type::Err;
612        };
613        let type_ = core_constant.to_type();
614        self.maybe_assert_type(&type_, expected, input.span());
615        type_
616    }
617
618    fn visit_associated_function(
619        &mut self,
620        input: &AssociatedFunctionExpression,
621        expected: &Self::AdditionalInput,
622    ) -> Self::Output {
623        // Check core struct name and function.
624        let Some(core_instruction) = self.get_core_function_call(input) else {
625            self.emit_err(TypeCheckerError::invalid_core_function_call(input, input.span()));
626            return Type::Err;
627        };
628        // Check that operation is not restricted to finalize blocks.
629        if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
630            && self.async_block_id.is_none()
631            && core_instruction.is_finalize_command()
632        {
633            self.emit_err(TypeCheckerError::operation_must_be_in_async_block_or_function(input.span()));
634        }
635
636        let return_type =
637            self.check_core_function_call(core_instruction.clone(), &input.arguments, expected, input.span());
638
639        // Check return type if the expected type is known.
640        self.maybe_assert_type(&return_type, expected, input.span());
641
642        // Await futures here so that can use the argument variable names to lookup.
643        if core_instruction == CoreFunction::FutureAwait && input.arguments.len() != 1 {
644            self.emit_err(TypeCheckerError::can_only_await_one_future_at_a_time(input.span));
645        }
646
647        return_type
648    }
649
650    fn visit_async(&mut self, input: &AsyncExpression, _additional: &Self::AdditionalInput) -> Self::Output {
651        // Step into an async block
652        self.async_block_id = Some(input.block.id);
653
654        // A few restrictions
655        if self.scope_state.is_conditional {
656            self.emit_err(TypeCheckerError::async_block_in_conditional(input.span));
657        }
658
659        if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
660            self.emit_err(TypeCheckerError::illegal_async_block_location(input.span));
661        }
662
663        if self.scope_state.already_contains_an_async_block {
664            self.emit_err(TypeCheckerError::multiple_async_blocks_not_allowed(input.span));
665        }
666
667        if self.scope_state.has_called_finalize {
668            self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
669        }
670
671        self.visit_block(&input.block);
672
673        // This scope now already has an async block
674        self.scope_state.already_contains_an_async_block = true;
675
676        // Step out of the async block
677        self.async_block_id = None;
678
679        // The type of the async block is just a `Future` with no `Location` (i.e. not produced by an explicit `async
680        // function`) and no inputs since we're not allowed to access inputs of a `Future` produced by an `async block.
681        Type::Future(FutureType::new(Vec::new(), None, false))
682    }
683
684    fn visit_binary(&mut self, input: &BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
685        let assert_same_type = |slf: &Self, t1: &Type, t2: &Type| -> Type {
686            if t1 == &Type::Err || t2 == &Type::Err {
687                Type::Err
688            } else if !t1.eq_user(t2) {
689                slf.emit_err(TypeCheckerError::operation_types_mismatch(input.op, t1, t2, input.span()));
690                Type::Err
691            } else {
692                t1.clone()
693            }
694        };
695
696        // This closure attempts to resolve numeric type inference between two operands.
697        // It handles the following cases:
698        // - If both types are unknown numeric placeholders (`Numeric`), emit errors for both.
699        // - If one type is `Numeric` and the other is an error (`Err`), propagate the error.
700        // - If one type is a known numeric type and the other is `Numeric`, infer the unknown type.
701        // - If one type is `Numeric` but the other is not a valid numeric type, emit an error.
702        // - Otherwise, do nothing (types are already resolved or not subject to inference).
703        let infer_numeric_types = |slf: &Self, left_type: &mut Type, right_type: &mut Type| {
704            use Type::*;
705
706            match (&*left_type, &*right_type) {
707                // Case: Both types are unknown numeric types – cannot infer either side
708                (Numeric, Numeric) => {
709                    slf.emit_inference_failure_error(left_type, &input.left);
710                    slf.emit_inference_failure_error(right_type, &input.right);
711                }
712
713                // Case: Left is unknown numeric, right is erroneous – propagate error to left
714                (Numeric, Err) => slf.emit_inference_failure_error(left_type, &input.left),
715
716                // Case: Right is unknown numeric, left is erroneous – propagate error to right
717                (Err, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
718
719                // Case: Right type is unknown numeric, infer it from known left type
720                (Integer(_) | Field | Group | Scalar, Numeric) => {
721                    *right_type = left_type.clone();
722                    slf.state.type_table.insert(input.right.id(), right_type.clone());
723                    if let Expression::Literal(literal) = &input.right {
724                        slf.check_numeric_literal(literal, right_type);
725                    }
726                }
727
728                // Case: Left type is unknown numeric, infer it from known right type
729                (Numeric, Integer(_) | Field | Group | Scalar) => {
730                    *left_type = right_type.clone();
731                    slf.state.type_table.insert(input.left.id(), left_type.clone());
732                    if let Expression::Literal(literal) = &input.left {
733                        slf.check_numeric_literal(literal, left_type);
734                    }
735                }
736
737                // Case: Left type is numeric but right is invalid for numeric inference – error on left
738                (Numeric, _) => slf.emit_inference_failure_error(left_type, &input.left),
739
740                // Case: Right type is numeric but left is invalid for numeric inference – error on right
741                (_, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
742
743                // No inference or error needed. Rely on further operator-specific checks.
744                _ => {}
745            }
746        };
747
748        match input.op {
749            BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
750                self.maybe_assert_type(&Type::Boolean, destination, input.span());
751                self.visit_expression(&input.left, &Some(Type::Boolean));
752                self.visit_expression(&input.right, &Some(Type::Boolean));
753                Type::Boolean
754            }
755            BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
756                let operand_expected = self.unwrap_optional_type(destination);
757
758                // The expected type for both `left` and `right` is the unwrapped type
759                let mut t1 = self.visit_expression(&input.left, &operand_expected);
760                let mut t2 = self.visit_expression(&input.right, &operand_expected);
761
762                // Infer `Numeric` types if possible
763                infer_numeric_types(self, &mut t1, &mut t2);
764
765                // Now sanity check everything
766                self.assert_bool_int_type(&t1, input.left.span());
767                self.assert_bool_int_type(&t2, input.right.span());
768
769                let result_t = assert_same_type(self, &t1, &t2);
770                self.maybe_assert_type(&result_t, destination, input.span());
771
772                self.wrap_if_optional(result_t, destination)
773            }
774            BinaryOperation::Add => {
775                let operand_expected = self.unwrap_optional_type(destination);
776
777                // The expected type for both `left` and `right` is the unwrapped type
778                let mut t1 = self.visit_expression(&input.left, &operand_expected);
779                let mut t2 = self.visit_expression(&input.right, &operand_expected);
780
781                // Infer `Numeric` types if possible
782                infer_numeric_types(self, &mut t1, &mut t2);
783
784                // Now sanity check everything
785                let assert_add_type = |type_: &Type, span: Span| {
786                    if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Scalar | Type::Integer(_)) {
787                        self.emit_err(TypeCheckerError::type_should_be2(
788                            type_,
789                            "a field, group, scalar, or integer",
790                            span,
791                        ));
792                    }
793                };
794
795                assert_add_type(&t1, input.left.span());
796                assert_add_type(&t2, input.right.span());
797
798                let result_t = assert_same_type(self, &t1, &t2);
799
800                self.maybe_assert_type(&result_t, destination, input.span());
801
802                self.wrap_if_optional(result_t, destination)
803            }
804            BinaryOperation::Sub => {
805                let operand_expected = self.unwrap_optional_type(destination);
806
807                // The expected type for both `left` and `right` is the unwrapped type
808                let mut t1 = self.visit_expression(&input.left, &operand_expected);
809                let mut t2 = self.visit_expression(&input.right, &operand_expected);
810
811                // Infer `Numeric` types if possible
812                infer_numeric_types(self, &mut t1, &mut t2);
813
814                // Now sanity check everything
815                self.assert_field_group_int_type(&t1, input.left.span());
816                self.assert_field_group_int_type(&t2, input.right.span());
817
818                let result_t = assert_same_type(self, &t1, &t2);
819
820                self.maybe_assert_type(&result_t, destination, input.span());
821
822                self.wrap_if_optional(result_t, destination)
823            }
824            BinaryOperation::Mul => {
825                let unwrapped_dest = self.unwrap_optional_type(destination);
826
827                // The expected type for both `left` and `right` is the same as unwrapped destination except when it is
828                // a `Type::Group`. In that case, the two operands should be a `Type::Group` and `Type::Scalar` but we can't
829                // known which one is which.
830                let expected = if matches!(unwrapped_dest, Some(Type::Group)) { &None } else { &unwrapped_dest };
831                let mut t1 = self.visit_expression(&input.left, expected);
832                let mut t2 = self.visit_expression(&input.right, expected);
833
834                // - If one side is `Group` and the other is an unresolved `Numeric`, infer the `Numeric` as a `Scalar`,
835                //   since `Group * Scalar = Group`.
836                // - Similarly, if one side is `Scalar` and the other is `Numeric`, infer the `Numeric` as `Group`.
837                //
838                // If no special case applies, default to inferring types between `t1` and `t2` as-is.
839                match (&t1, &t2) {
840                    (Type::Group, Type::Numeric) => infer_numeric_types(self, &mut Type::Scalar, &mut t2),
841                    (Type::Numeric, Type::Group) => infer_numeric_types(self, &mut t1, &mut Type::Scalar),
842                    (Type::Scalar, Type::Numeric) => infer_numeric_types(self, &mut Type::Group, &mut t2),
843                    (Type::Numeric, Type::Scalar) => infer_numeric_types(self, &mut t1, &mut Type::Group),
844                    (_, _) => infer_numeric_types(self, &mut t1, &mut t2),
845                }
846
847                // Final sanity checks
848                let result_t = match (&t1, &t2) {
849                    (Type::Err, _) | (_, Type::Err) => Type::Err,
850                    (Type::Group, Type::Scalar) | (Type::Scalar, Type::Group) => Type::Group,
851                    (Type::Field, Type::Field) => Type::Field,
852                    (Type::Integer(integer_type1), Type::Integer(integer_type2)) if integer_type1 == integer_type2 => {
853                        t1.clone()
854                    }
855                    _ => {
856                        self.emit_err(TypeCheckerError::mul_types_mismatch(t1, t2, input.span()));
857                        Type::Err
858                    }
859                };
860
861                self.maybe_assert_type(&result_t, destination, input.span());
862
863                self.wrap_if_optional(result_t, destination)
864            }
865            BinaryOperation::Div => {
866                let operand_expected = self.unwrap_optional_type(destination);
867
868                // The expected type for both `left` and `right` is the unwrapped type
869                let mut t1 = self.visit_expression(&input.left, &operand_expected);
870                let mut t2 = self.visit_expression(&input.right, &operand_expected);
871
872                // Infer `Numeric` types if possible
873                infer_numeric_types(self, &mut t1, &mut t2);
874
875                // Now sanity check everything
876                self.assert_field_int_type(&t1, input.left.span());
877                self.assert_field_int_type(&t2, input.right.span());
878
879                let result_t = assert_same_type(self, &t1, &t2);
880
881                self.maybe_assert_type(&result_t, destination, input.span());
882
883                self.wrap_if_optional(result_t, destination)
884            }
885            BinaryOperation::Rem | BinaryOperation::RemWrapped => {
886                let operand_expected = self.unwrap_optional_type(destination);
887
888                // The expected type for both `left` and `right` is the unwrapped type
889                let mut t1 = self.visit_expression(&input.left, &operand_expected);
890                let mut t2 = self.visit_expression(&input.right, &operand_expected);
891
892                // Infer `Numeric` types if possible
893                infer_numeric_types(self, &mut t1, &mut t2);
894
895                // Now sanity check everything
896                self.assert_int_type(&t1, input.left.span());
897                self.assert_int_type(&t2, input.right.span());
898
899                let result_t = assert_same_type(self, &t1, &t2);
900
901                self.maybe_assert_type(&result_t, destination, input.span());
902
903                self.wrap_if_optional(result_t, destination)
904            }
905            BinaryOperation::Mod => {
906                let operand_expected = self.unwrap_optional_type(destination);
907
908                // The expected type for both `left` and `right` is the unwrapped type
909                let mut t1 = self.visit_expression(&input.left, &operand_expected);
910                let mut t2 = self.visit_expression(&input.right, &operand_expected);
911
912                // Infer `Numeric` types if possible
913                infer_numeric_types(self, &mut t1, &mut t2);
914
915                // Now sanity check everything
916                self.assert_unsigned_type(&t1, input.left.span());
917                self.assert_unsigned_type(&t2, input.right.span());
918
919                let result_t = assert_same_type(self, &t1, &t2);
920
921                self.maybe_assert_type(&result_t, destination, input.span());
922
923                self.wrap_if_optional(result_t, destination)
924            }
925            BinaryOperation::Pow => {
926                let operand_expected = self.unwrap_optional_type(destination);
927
928                // The expected type of `left` is the unwrapped destination
929                let mut t1 = self.visit_expression(&input.left, &operand_expected);
930
931                // The expected type of `right` is `field`, `u8`, `u16`, or `u32` so leave it as `None` for now.
932                let mut t2 = self.visit_expression(&input.right, &None);
933
934                // If one side is a `Field` and the other is a `Numeric`, infer the `Numeric` as a `Field.
935                // Otherwise, error out for each `Numeric`.
936                if matches!((&t1, &t2), (Type::Field, Type::Numeric) | (Type::Numeric, Type::Field)) {
937                    infer_numeric_types(self, &mut t1, &mut t2);
938                } else {
939                    if matches!(t1, Type::Numeric) {
940                        self.emit_inference_failure_error(&mut t1, &input.left);
941                    }
942                    if matches!(t2, Type::Numeric) {
943                        self.emit_inference_failure_error(&mut t2, &input.right);
944                    }
945                }
946
947                // Now sanity check everything
948                let ty = match (&t1, &t2) {
949                    (Type::Err, _) | (_, Type::Err) => Type::Err,
950                    (Type::Field, Type::Field) => Type::Field,
951                    (base @ Type::Integer(_), t2) => {
952                        if !matches!(
953                            t2,
954                            Type::Integer(IntegerType::U8)
955                                | Type::Integer(IntegerType::U16)
956                                | Type::Integer(IntegerType::U32)
957                        ) {
958                            self.emit_err(TypeCheckerError::pow_types_mismatch(base, t2, input.span()));
959                        }
960                        base.clone()
961                    }
962                    _ => {
963                        self.emit_err(TypeCheckerError::pow_types_mismatch(t1, t2, input.span()));
964                        Type::Err
965                    }
966                };
967
968                self.maybe_assert_type(&ty, destination, input.span());
969
970                self.wrap_if_optional(ty, destination)
971            }
972            BinaryOperation::Eq | BinaryOperation::Neq => {
973                // Handle type inference for `None` as a special case.
974                //
975                // If either side of the binary expression is the literal `None`, we first type check the other side
976                // without any expected type to infer its type. Then we type check the `None` side using that inferred type
977                // as context, in hopes of resolving it to a more specific optional type.
978                //
979                // This helps with cases like `x == None`, allowing us to infer the type of `x` and apply it to `None`.
980                // However, this is **not sufficient for the general case**. For instance, in something like `[None] == [x]`,
981                // we won't be able to infer the type of `None`.
982                let (mut t1, mut t2) =
983                    if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.right {
984                        let t1 = self.visit_expression(&input.left, &None);
985                        (t1.clone(), self.visit_expression(&input.right, &Some(t1.clone())))
986                    } else if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.left {
987                        let t2 = self.visit_expression(&input.right, &None);
988                        (self.visit_expression(&input.left, &Some(t2.clone())), t2)
989                    } else {
990                        (self.visit_expression(&input.left, &None), self.visit_expression(&input.right, &None))
991                    };
992
993                // Infer `Numeric` types if possible
994                infer_numeric_types(self, &mut t1, &mut t2);
995
996                // Now sanity check everything
997                let _ = assert_same_type(self, &t1, &t2);
998
999                self.maybe_assert_type(&Type::Boolean, destination, input.span());
1000
1001                Type::Boolean
1002            }
1003            BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Lte | BinaryOperation::Gte => {
1004                // Assert left and right are equal field, scalar, or integer types.
1005                let mut t1 = self.visit_expression(&input.left, &None);
1006                let mut t2 = self.visit_expression(&input.right, &None);
1007
1008                // Infer `Numeric` types if possible
1009                infer_numeric_types(self, &mut t1, &mut t2);
1010
1011                // Now sanity check everything
1012                let assert_compare_type = |type_: &Type, span: Span| {
1013                    if !matches!(type_, Type::Err | Type::Field | Type::Scalar | Type::Integer(_)) {
1014                        self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, scalar, or integer", span));
1015                    }
1016                };
1017
1018                assert_compare_type(&t1, input.left.span());
1019                assert_compare_type(&t2, input.right.span());
1020
1021                let _ = assert_same_type(self, &t1, &t2);
1022
1023                self.maybe_assert_type(&Type::Boolean, destination, input.span());
1024
1025                Type::Boolean
1026            }
1027            BinaryOperation::AddWrapped
1028            | BinaryOperation::SubWrapped
1029            | BinaryOperation::DivWrapped
1030            | BinaryOperation::MulWrapped => {
1031                let operand_expected = self.unwrap_optional_type(destination);
1032
1033                // The expected type for both `left` and `right` is the unwrapped type
1034                let mut t1 = self.visit_expression(&input.left, &operand_expected);
1035                let mut t2 = self.visit_expression(&input.right, &operand_expected);
1036
1037                // Infer `Numeric` types if possible
1038                infer_numeric_types(self, &mut t1, &mut t2);
1039
1040                // Now sanity check everything
1041                self.assert_int_type(&t1, input.left.span());
1042                self.assert_int_type(&t2, input.right.span());
1043
1044                let result_t = assert_same_type(self, &t1, &t2);
1045
1046                self.maybe_assert_type(&result_t, destination, input.span());
1047
1048                self.wrap_if_optional(result_t, destination)
1049            }
1050            BinaryOperation::Shl
1051            | BinaryOperation::ShlWrapped
1052            | BinaryOperation::Shr
1053            | BinaryOperation::ShrWrapped
1054            | BinaryOperation::PowWrapped => {
1055                let operand_expected = self.unwrap_optional_type(destination);
1056
1057                // The expected type of `left` is the unwrapped `destination`
1058                let t1 = self.visit_expression_reject_numeric(&input.left, &operand_expected);
1059
1060                // The expected type of `right` is `field`, `u8`, `u16`, or `u32` so leave it as `None` for now.
1061                let t2 = self.visit_expression_reject_numeric(&input.right, &None);
1062
1063                self.assert_int_type(&t1, input.left.span());
1064
1065                if !matches!(
1066                    &t2,
1067                    Type::Err
1068                        | Type::Integer(IntegerType::U8)
1069                        | Type::Integer(IntegerType::U16)
1070                        | Type::Integer(IntegerType::U32)
1071                ) {
1072                    self.emit_err(TypeCheckerError::shift_type_magnitude(input.op, t2, input.right.span()));
1073                }
1074
1075                self.wrap_if_optional(t1, destination)
1076            }
1077        }
1078    }
1079
1080    fn visit_call(&mut self, input: &CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
1081        let callee_program = input.program.or(self.scope_state.program_name).unwrap();
1082
1083        let callee_path = input.function.absolute_path();
1084
1085        let Some(func_symbol) =
1086            self.state.symbol_table.lookup_function(&Location::new(callee_program, callee_path.clone()))
1087        else {
1088            self.emit_err(TypeCheckerError::unknown_sym("function", input.function.clone(), input.function.span()));
1089            return Type::Err;
1090        };
1091
1092        let func = func_symbol.function.clone();
1093
1094        // Check that the call is valid.
1095        // We always set the variant before entering the body of a function, so this unwrap works.
1096        match self.scope_state.variant.unwrap() {
1097            Variant::AsyncFunction | Variant::Function if !matches!(func.variant, Variant::Inline) => self.emit_err(
1098                TypeCheckerError::can_only_call_inline_function("a `function`, `inline`, or `constructor`", input.span),
1099            ),
1100            Variant::Transition | Variant::AsyncTransition
1101                if matches!(func.variant, Variant::Transition)
1102                    && input.program.is_none_or(|program| program == self.scope_state.program_name.unwrap()) =>
1103            {
1104                self.emit_err(TypeCheckerError::cannot_invoke_call_to_local_transition_function(input.span))
1105            }
1106            _ => {}
1107        }
1108
1109        // Check that the call is not to an external `inline` function.
1110        if func.variant == Variant::Inline
1111            && input.program.is_some_and(|program| program != self.scope_state.program_name.unwrap())
1112        {
1113            self.emit_err(TypeCheckerError::cannot_call_external_inline_function(input.span));
1114        }
1115
1116        // Make sure we're not calling a non-inline from an async block
1117        if self.async_block_id.is_some() && !matches!(func.variant, Variant::Inline) {
1118            self.emit_err(TypeCheckerError::can_only_call_inline_function("an async block", input.span));
1119        }
1120
1121        // Async functions return a single future.
1122        let mut ret = if func.variant == Variant::AsyncFunction {
1123            // Async functions always return futures.
1124            Type::Future(FutureType::new(
1125                Vec::new(),
1126                Some(Location::new(callee_program, input.function.absolute_path())),
1127                false,
1128            ))
1129        } else if func.variant == Variant::AsyncTransition {
1130            // Fully infer future type.
1131            let Some(inputs) =
1132                self.async_function_input_types.get(&Location::new(callee_program, vec![Symbol::intern(&format!(
1133                    "finalize/{}",
1134                    input.function.identifier().name
1135                ))]))
1136            else {
1137                self.emit_err(TypeCheckerError::async_function_not_found(input.function.clone(), input.span));
1138                return Type::Future(FutureType::new(
1139                    Vec::new(),
1140                    Some(Location::new(callee_program, callee_path.clone())),
1141                    false,
1142                ));
1143            };
1144
1145            let future_type = Type::Future(FutureType::new(
1146                inputs.clone(),
1147                Some(Location::new(callee_program, callee_path.clone())),
1148                true,
1149            ));
1150            let fully_inferred_type = match &func.output_type {
1151                Type::Tuple(tup) => Type::Tuple(TupleType::new(
1152                    tup.elements()
1153                        .iter()
1154                        .map(|t| if matches!(t, Type::Future(_)) { future_type.clone() } else { t.clone() })
1155                        .collect::<Vec<Type>>(),
1156                )),
1157                Type::Future(_) => future_type,
1158                _ => panic!("Invalid output type for async transition."),
1159            };
1160            self.assert_and_return_type(fully_inferred_type, expected, input.span())
1161        } else {
1162            self.assert_and_return_type(func.output_type, expected, input.span())
1163        };
1164
1165        // Check number of function arguments.
1166        if func.input.len() != input.arguments.len() {
1167            self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
1168                func.input.len(),
1169                input.arguments.len(),
1170                input.span(),
1171            ));
1172        }
1173
1174        // Check the number of const arguments against the number of the function's const parameters
1175        if func.const_parameters.len() != input.const_arguments.len() {
1176            self.emit_err(TypeCheckerError::incorrect_num_const_args(
1177                "Call",
1178                func.const_parameters.len(),
1179                input.const_arguments.len(),
1180                input.span(),
1181            ));
1182        }
1183
1184        // Check the types of const arguments against the types of the function's const parameters
1185        for (expected, argument) in func.const_parameters.iter().zip(input.const_arguments.iter()) {
1186            self.visit_expression(argument, &Some(expected.type_().clone()));
1187        }
1188
1189        let (mut input_futures, mut inferred_finalize_inputs) = (Vec::new(), Vec::new());
1190        for (expected, argument) in func.input.iter().zip(input.arguments.iter()) {
1191            // Get the type of the expression. If the type is not known, do not attempt to attempt any further inference.
1192            let ty = self.visit_expression(argument, &Some(expected.type_().clone()));
1193
1194            if ty == Type::Err {
1195                return Type::Err;
1196            }
1197            // Extract information about futures that are being consumed.
1198            if func.variant == Variant::AsyncFunction && matches!(expected.type_(), Type::Future(_)) {
1199                // Consume the future.
1200                let option_name = match argument {
1201                    Expression::Path(path) => Some(path.identifier().name),
1202                    Expression::TupleAccess(tuple_access) => {
1203                        if let Expression::Path(path) = &tuple_access.tuple {
1204                            Some(path.identifier().name)
1205                        } else {
1206                            None
1207                        }
1208                    }
1209                    _ => None,
1210                };
1211
1212                if let Some(name) = option_name {
1213                    match self.scope_state.futures.shift_remove(&name) {
1214                        Some(future) => {
1215                            self.scope_state.call_location = Some(future);
1216                        }
1217                        None => {
1218                            self.emit_err(TypeCheckerError::unknown_future_consumed(name, argument.span()));
1219                        }
1220                    }
1221                }
1222
1223                match argument {
1224                    Expression::Path(_) | Expression::Call(_) | Expression::TupleAccess(_) => {
1225                        match &self.scope_state.call_location {
1226                            Some(location) => {
1227                                // Get the external program and function name.
1228                                input_futures.push(location.clone());
1229                                // Get the full inferred type.
1230                                inferred_finalize_inputs.push(ty);
1231                            }
1232                            None => {
1233                                self.emit_err(TypeCheckerError::unknown_future_consumed(argument, argument.span()));
1234                            }
1235                        }
1236                    }
1237                    _ => {
1238                        self.emit_err(TypeCheckerError::unknown_future_consumed("unknown", argument.span()));
1239                    }
1240                }
1241            } else {
1242                inferred_finalize_inputs.push(ty);
1243            }
1244        }
1245
1246        let caller_program =
1247            self.scope_state.program_name.expect("`program_name` is always set before traversing a program scope");
1248        // Note: Constructors are added to the call graph under the `constructor` symbol.
1249        // This is safe since `constructor` is a reserved token and cannot be used as a function name.
1250        let caller_function = if self.scope_state.is_constructor {
1251            sym::constructor
1252        } else {
1253            self.scope_state.function.expect("`function` is always set before traversing a function scope")
1254        };
1255
1256        // This is the path to the function that we're in
1257        let caller_path = self
1258            .scope_state
1259            .module_name
1260            .iter()
1261            .cloned()
1262            .chain(std::iter::once(caller_function))
1263            .collect::<Vec<Symbol>>();
1264
1265        let caller = Location::new(caller_program, caller_path.clone());
1266        let callee = Location::new(callee_program, callee_path.clone());
1267        self.state.call_graph.add_edge(caller, callee);
1268
1269        if func.variant.is_transition() && self.scope_state.variant == Some(Variant::AsyncTransition) {
1270            if self.scope_state.has_called_finalize {
1271                self.emit_err(TypeCheckerError::external_call_after_async("function call", input.span));
1272            }
1273
1274            if self.scope_state.already_contains_an_async_block {
1275                self.emit_err(TypeCheckerError::external_call_after_async("block", input.span));
1276            }
1277        }
1278
1279        // Propagate futures from async functions and transitions.
1280        if func.variant.is_async_function() {
1281            // Cannot have async calls in a conditional block.
1282            if self.scope_state.is_conditional {
1283                self.emit_err(TypeCheckerError::async_call_in_conditional(input.span));
1284            }
1285
1286            // Can only call async functions and external async transitions from an async transition body.
1287            if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
1288                self.emit_err(TypeCheckerError::async_call_can_only_be_done_from_async_transition(input.span));
1289            }
1290
1291            // Can only call an async function once in a transition function body.
1292            if self.scope_state.has_called_finalize {
1293                self.emit_err(TypeCheckerError::must_call_async_function_once(input.span));
1294            }
1295
1296            if self.scope_state.already_contains_an_async_block {
1297                self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
1298            }
1299
1300            // Check that all futures consumed.
1301            if !self.scope_state.futures.is_empty() {
1302                self.emit_err(TypeCheckerError::not_all_futures_consumed(
1303                    self.scope_state.futures.iter().map(|(f, _)| f).join(", "),
1304                    input.span,
1305                ));
1306            }
1307            self.state
1308                .symbol_table
1309                .attach_finalizer(
1310                    Location::new(callee_program, caller_path),
1311                    Location::new(callee_program, callee_path.clone()),
1312                    input_futures,
1313                    inferred_finalize_inputs.clone(),
1314                )
1315                .expect("Failed to attach finalizer");
1316            // Create expectation for finalize inputs that will be checked when checking corresponding finalize function signature.
1317            self.async_function_callers
1318                .entry(Location::new(self.scope_state.program_name.unwrap(), callee_path.clone()))
1319                .or_default()
1320                .insert(self.scope_state.location());
1321
1322            // Set scope state flag.
1323            self.scope_state.has_called_finalize = true;
1324
1325            // Update ret to reflect fully inferred future type.
1326            ret = Type::Future(FutureType::new(
1327                inferred_finalize_inputs,
1328                Some(Location::new(callee_program, callee_path.clone())),
1329                true,
1330            ));
1331
1332            // Type check in case the expected type is known.
1333            self.assert_and_return_type(ret.clone(), expected, input.span());
1334        }
1335
1336        // Set call location so that definition statement knows where future comes from.
1337        self.scope_state.call_location = Some(Location::new(callee_program, callee_path.clone()));
1338
1339        ret
1340    }
1341
1342    fn visit_cast(&mut self, input: &CastExpression, expected: &Self::AdditionalInput) -> Self::Output {
1343        let expression_type = self.visit_expression_reject_numeric(&input.expression, &None);
1344
1345        let assert_castable_type = |actual: &Type, span: Span| {
1346            if !matches!(
1347                actual,
1348                Type::Integer(_) | Type::Boolean | Type::Field | Type::Group | Type::Scalar | Type::Address | Type::Err,
1349            ) {
1350                self.emit_err(TypeCheckerError::type_should_be2(
1351                    actual,
1352                    "an integer, bool, field, group, scalar, or address",
1353                    span,
1354                ));
1355            }
1356        };
1357
1358        assert_castable_type(&input.type_, input.span());
1359
1360        assert_castable_type(&expression_type, input.expression.span());
1361
1362        self.maybe_assert_type(&input.type_, expected, input.span());
1363
1364        input.type_.clone()
1365    }
1366
1367    fn visit_struct_init(&mut self, input: &StructExpression, additional: &Self::AdditionalInput) -> Self::Output {
1368        let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
1369        let Some(struct_) = struct_ else {
1370            self.emit_err(TypeCheckerError::unknown_sym("struct or record", input.path.clone(), input.path.span()));
1371            return Type::Err;
1372        };
1373
1374        // Check the number of const arguments against the number of the struct's const parameters
1375        if struct_.const_parameters.len() != input.const_arguments.len() {
1376            self.emit_err(TypeCheckerError::incorrect_num_const_args(
1377                "Struct expression",
1378                struct_.const_parameters.len(),
1379                input.const_arguments.len(),
1380                input.span(),
1381            ));
1382        }
1383
1384        // Check the types of const arguments against the types of the struct's const parameters
1385        for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
1386            self.visit_expression(argument, &Some(expected.type_().clone()));
1387        }
1388
1389        // Note that it is sufficient for the `program` to be `None` as composite types can only be initialized
1390        // in the program in which they are defined.
1391        let type_ = Type::Composite(CompositeType {
1392            path: input.path.clone(),
1393            const_arguments: input.const_arguments.clone(),
1394            program: None,
1395        });
1396        self.maybe_assert_type(&type_, additional, input.path.span());
1397
1398        // Check number of struct members.
1399        if struct_.members.len() != input.members.len() {
1400            self.emit_err(TypeCheckerError::incorrect_num_struct_members(
1401                struct_.members.len(),
1402                input.members.len(),
1403                input.span(),
1404            ));
1405        }
1406
1407        for Member { identifier, type_, .. } in struct_.members.iter() {
1408            if let Some(actual) = input.members.iter().find(|member| member.identifier.name == identifier.name) {
1409                match &actual.expression {
1410                    None => {
1411                        // If `expression` is None, then the member uses the identifier shorthand, e.g. `Foo { a }`
1412                        // We visit it as an expression rather than just calling `visit_path` so it will get
1413                        // put into the type table.
1414                        self.visit_expression(
1415                            &Path::from(actual.identifier)
1416                                .with_absolute_path(Some(
1417                                    self.scope_state
1418                                        .module_name
1419                                        .iter()
1420                                        .cloned()
1421                                        .chain(std::iter::once(actual.identifier.name))
1422                                        .collect::<Vec<Symbol>>(),
1423                                ))
1424                                .into(),
1425                            &Some(type_.clone()),
1426                        );
1427                    }
1428                    Some(expr) => {
1429                        // Otherwise, visit the associated expression.
1430                        self.visit_expression(expr, &Some(type_.clone()));
1431                    }
1432                };
1433            } else {
1434                self.emit_err(TypeCheckerError::missing_struct_member(struct_.identifier, identifier, input.span()));
1435            };
1436        }
1437
1438        if struct_.is_record {
1439            // First, ensure that the current scope is not an async function. Records should not be instantiated in
1440            // async functions
1441            if self.scope_state.variant == Some(Variant::AsyncFunction) {
1442                self.state
1443                    .handler
1444                    .emit_err(TypeCheckerError::records_not_allowed_inside_async("function", input.span()));
1445            }
1446
1447            // Similarly, ensure that the current scope is not an async block. Records should not be instantiated in
1448            // async blocks
1449            if self.async_block_id.is_some() {
1450                self.state.handler.emit_err(TypeCheckerError::records_not_allowed_inside_async("block", input.span()));
1451            }
1452
1453            // Records where the `owner` is `self.caller` can be problematic because `self.caller` can be a program
1454            // address and programs can't spend records. Emit a warning in this case.
1455            //
1456            // Multiple occurrences of `owner` here is an error but that should be flagged somewhere else.
1457            input.members.iter().filter(|init| init.identifier.name == sym::owner).for_each(|init| {
1458                if let Some(Expression::MemberAccess(access)) = &init.expression
1459                    && let MemberAccess {
1460                        inner: Expression::Path(path),
1461                        name: Identifier { name: sym::caller, .. },
1462                        ..
1463                    } = &**access
1464                    && path.identifier().name == sym::SelfLower
1465                {
1466                    self.emit_warning(TypeCheckerWarning::caller_as_record_owner(input.path.clone(), access.span()));
1467                }
1468            });
1469        }
1470
1471        type_
1472    }
1473
1474    // We do not want to panic on `ErrExpression`s in order to propagate as many errors as possible.
1475    fn visit_err(&mut self, _input: &ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1476        Type::Err
1477    }
1478
1479    fn visit_path(&mut self, input: &Path, expected: &Self::AdditionalInput) -> Self::Output {
1480        let var = self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path());
1481
1482        if let Some(var) = var {
1483            if var.declaration == VariableType::Storage && !var.type_.is_vector() && !var.type_.is_mapping() {
1484                self.check_access_allowed("storage access", true, input.span());
1485            }
1486
1487            self.maybe_assert_type(&var.type_, expected, input.span());
1488            var.type_.clone()
1489        } else {
1490            self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span()));
1491            Type::Err
1492        }
1493    }
1494
1495    fn visit_literal(&mut self, input: &Literal, expected: &Self::AdditionalInput) -> Self::Output {
1496        let span = input.span();
1497
1498        macro_rules! parse_and_return {
1499            ($ty:ty, $variant:expr, $str:expr, $label:expr) => {{
1500                self.parse_integer_literal::<$ty>($str, span, $label);
1501                Type::Integer($variant)
1502            }};
1503        }
1504
1505        let type_ = match &input.variant {
1506            LiteralVariant::Address(..) => Type::Address,
1507            LiteralVariant::Boolean(..) => Type::Boolean,
1508            LiteralVariant::Field(..) => Type::Field,
1509            LiteralVariant::Scalar(..) => Type::Scalar,
1510            LiteralVariant::String(..) => Type::String,
1511            LiteralVariant::Integer(kind, string) => match kind {
1512                IntegerType::U8 => parse_and_return!(u8, IntegerType::U8, string, "u8"),
1513                IntegerType::U16 => parse_and_return!(u16, IntegerType::U16, string, "u16"),
1514                IntegerType::U32 => parse_and_return!(u32, IntegerType::U32, string, "u32"),
1515                IntegerType::U64 => parse_and_return!(u64, IntegerType::U64, string, "u64"),
1516                IntegerType::U128 => parse_and_return!(u128, IntegerType::U128, string, "u128"),
1517                IntegerType::I8 => parse_and_return!(i8, IntegerType::I8, string, "i8"),
1518                IntegerType::I16 => parse_and_return!(i16, IntegerType::I16, string, "i16"),
1519                IntegerType::I32 => parse_and_return!(i32, IntegerType::I32, string, "i32"),
1520                IntegerType::I64 => parse_and_return!(i64, IntegerType::I64, string, "i64"),
1521                IntegerType::I128 => parse_and_return!(i128, IntegerType::I128, string, "i128"),
1522            },
1523            LiteralVariant::Group(s) => {
1524                let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1525                if !trimmed.is_empty()
1526                    && format!("{trimmed}group")
1527                        .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1528                        .is_err()
1529                {
1530                    self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1531                }
1532                Type::Group
1533            }
1534            LiteralVariant::Unsuffixed(_) => match expected {
1535                Some(ty @ Type::Integer(_) | ty @ Type::Field | ty @ Type::Group | ty @ Type::Scalar) => {
1536                    self.check_numeric_literal(input, ty);
1537                    ty.clone()
1538                }
1539                Some(ty @ Type::Optional(opt)) => {
1540                    // Handle optional expected type, e.g., u32?
1541                    let inner = &opt.inner;
1542                    match &**inner {
1543                        Type::Integer(_) | Type::Field | Type::Group | Type::Scalar => {
1544                            self.check_numeric_literal(input, inner);
1545                            Type::Optional(OptionalType { inner: Box::new(*inner.clone()) })
1546                        }
1547                        _ => {
1548                            self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(
1549                                format!("type `{ty}`"),
1550                                span,
1551                            ));
1552                            Type::Err
1553                        }
1554                    }
1555                }
1556                Some(ty) => {
1557                    self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(format!("type `{ty}`"), span));
1558                    Type::Err
1559                }
1560                None => Type::Numeric,
1561            },
1562            LiteralVariant::None => {
1563                if let Some(ty @ Type::Optional(_)) = expected {
1564                    ty.clone()
1565                } else if let Some(ty) = expected {
1566                    self.emit_err(TypeCheckerError::none_found_non_optional(format!("{ty}"), span));
1567                    Type::Err
1568                } else {
1569                    self.emit_err(TypeCheckerError::could_not_determine_type(format!("{input}"), span));
1570                    Type::Err
1571                }
1572            }
1573        };
1574
1575        self.maybe_assert_type(&type_, expected, span);
1576
1577        type_
1578    }
1579
1580    fn visit_locator(&mut self, input: &LocatorExpression, expected: &Self::AdditionalInput) -> Self::Output {
1581        let maybe_var =
1582            self.state.symbol_table.lookup_global(&Location::new(input.program.name.name, vec![input.name])).cloned();
1583        if let Some(var) = maybe_var {
1584            self.maybe_assert_type(&var.type_, expected, input.span());
1585            var.type_
1586        } else {
1587            self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));
1588            Type::Err
1589        }
1590    }
1591
1592    fn visit_ternary(&mut self, input: &TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
1593        self.visit_expression(&input.condition, &Some(Type::Boolean));
1594
1595        // We try to coerce one side to another in the ternary operator whenever possible and/or needed.
1596        let (t1, t2) = if expected.is_some() {
1597            (
1598                self.visit_expression_reject_numeric(&input.if_true, expected),
1599                self.visit_expression_reject_numeric(&input.if_false, expected),
1600            )
1601        } else if input.if_false.is_none_expr() {
1602            let t1 = self.visit_expression(&input.if_true, &None);
1603            if matches!(t1, Type::Optional(_)) {
1604                (t1.clone(), self.visit_expression(&input.if_false, &Some(t1.clone())))
1605            } else {
1606                (
1607                    t1.clone(),
1608                    self.visit_expression(
1609                        &input.if_false,
1610                        &Some(Type::Optional(OptionalType { inner: Box::new(t1.clone()) })),
1611                    ),
1612                )
1613            }
1614        } else if input.if_true.is_none_expr() {
1615            let t2 = self.visit_expression(&input.if_false, &None);
1616            if matches!(t2, Type::Optional(_)) {
1617                (t2.clone(), self.visit_expression(&input.if_true, &Some(t2.clone())))
1618            } else {
1619                (
1620                    t2.clone(),
1621                    self.visit_expression(
1622                        &input.if_true,
1623                        &Some(Type::Optional(OptionalType { inner: Box::new(t2.clone()) })),
1624                    ),
1625                )
1626            }
1627        } else {
1628            (
1629                self.visit_expression_reject_numeric(&input.if_true, &None),
1630                self.visit_expression_reject_numeric(&input.if_false, &None),
1631            )
1632        };
1633
1634        let typ = if t1 == Type::Err || t2 == Type::Err {
1635            Type::Err
1636        } else if !t1.can_coerce_to(&t2) && !t2.can_coerce_to(&t1) {
1637            self.emit_err(TypeCheckerError::ternary_branch_mismatch(t1, t2, input.span()));
1638            Type::Err
1639        } else if let Some(expected) = expected {
1640            expected.clone()
1641        } else if t1.can_coerce_to(&t2) {
1642            t2
1643        } else {
1644            t1
1645        };
1646
1647        // Make sure this isn't an external record type - won't work as we can't construct it.
1648        if self.is_external_record(&typ) {
1649            self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1650        }
1651
1652        // None of its members may be external record types either.
1653        if let Type::Tuple(tuple) = &typ
1654            && tuple.elements().iter().any(|ty| self.is_external_record(ty))
1655        {
1656            self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1657        }
1658
1659        typ
1660    }
1661
1662    fn visit_tuple(&mut self, input: &TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
1663        if let Some(expected) = expected {
1664            if let Type::Tuple(expected_types) = expected {
1665                // If the expected type is a tuple, then ensure it's compatible with `input`
1666
1667                // First, make sure that the number of tuple elements is correct
1668                if expected_types.length() != input.elements.len() {
1669                    self.emit_err(TypeCheckerError::incorrect_tuple_length(
1670                        expected_types.length(),
1671                        input.elements.len(),
1672                        input.span(),
1673                    ));
1674                }
1675
1676                // Now make sure that none of the tuple elements is a tuple
1677                input.elements.iter().zip(expected_types.elements()).for_each(|(expr, expected_el_ty)| {
1678                    if matches!(expr, Expression::Tuple(_)) {
1679                        self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1680                    }
1681                    self.visit_expression(expr, &Some(expected_el_ty.clone()));
1682                });
1683
1684                // Just return the expected type since we proved it's correct
1685                expected.clone()
1686            } else {
1687                // If the expected type is not a tuple, then we just error out
1688
1689                // This is the expected type of the tuple based on its individual fields
1690                let field_types = input
1691                    .elements
1692                    .iter()
1693                    .map(|field| {
1694                        let ty = self.visit_expression(field, &None);
1695                        if ty == Type::Numeric {
1696                            self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1697                            Type::Err
1698                        } else {
1699                            ty
1700                        }
1701                    })
1702                    .collect::<Vec<_>>();
1703                if field_types.iter().all(|f| *f != Type::Err) {
1704                    let tuple_type = Type::Tuple(TupleType::new(field_types));
1705                    self.emit_err(TypeCheckerError::type_should_be2(tuple_type, expected, input.span()));
1706                }
1707
1708                // Recover with the expected type anyways
1709                expected.clone()
1710            }
1711        } else {
1712            // If no `expected` type is provided, then we analyze the tuple itself and infer its type
1713
1714            // We still need to check that none of the tuple elements is a tuple
1715            input.elements.iter().for_each(|expr| {
1716                if matches!(expr, Expression::Tuple(_)) {
1717                    self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1718                }
1719            });
1720
1721            Type::Tuple(TupleType::new(
1722                input
1723                    .elements
1724                    .iter()
1725                    .map(|field| {
1726                        let ty = self.visit_expression(field, &None);
1727                        if ty == Type::Numeric {
1728                            self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1729                            Type::Err
1730                        } else {
1731                            ty
1732                        }
1733                    })
1734                    .collect::<Vec<_>>(),
1735            ))
1736        }
1737    }
1738
1739    fn visit_unary(&mut self, input: &UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
1740        let operand_expected = self.unwrap_optional_type(destination);
1741
1742        let assert_signed_int = |slf: &mut Self, type_: &Type| {
1743            if !matches!(
1744                type_,
1745                Type::Err
1746                    | Type::Integer(IntegerType::I8)
1747                    | Type::Integer(IntegerType::I16)
1748                    | Type::Integer(IntegerType::I32)
1749                    | Type::Integer(IntegerType::I64)
1750                    | Type::Integer(IntegerType::I128)
1751            ) {
1752                slf.emit_err(TypeCheckerError::type_should_be2(type_, "a signed integer", input.span()));
1753            }
1754        };
1755
1756        let ty = match input.op {
1757            UnaryOperation::Abs => {
1758                let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1759                assert_signed_int(self, &type_);
1760                type_
1761            }
1762            UnaryOperation::AbsWrapped => {
1763                let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1764                assert_signed_int(self, &type_);
1765                type_
1766            }
1767            UnaryOperation::Double => {
1768                let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1769                if !matches!(&type_, Type::Err | Type::Field | Type::Group) {
1770                    self.emit_err(TypeCheckerError::type_should_be2(&type_, "a field or group", input.span()));
1771                }
1772                type_
1773            }
1774            UnaryOperation::Inverse => {
1775                let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1776                if type_ == Type::Numeric {
1777                    // We can actually infer to `field` here because only fields can be inverted
1778                    type_ = Type::Field;
1779                    self.state.type_table.insert(input.receiver.id(), Type::Field);
1780                } else {
1781                    self.assert_type(&type_, &Type::Field, input.span());
1782                }
1783                type_
1784            }
1785            UnaryOperation::Negate => {
1786                let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1787                if !matches!(
1788                    &type_,
1789                    Type::Err
1790                        | Type::Integer(IntegerType::I8)
1791                        | Type::Integer(IntegerType::I16)
1792                        | Type::Integer(IntegerType::I32)
1793                        | Type::Integer(IntegerType::I64)
1794                        | Type::Integer(IntegerType::I128)
1795                        | Type::Group
1796                        | Type::Field
1797                ) {
1798                    self.emit_err(TypeCheckerError::type_should_be2(
1799                        &type_,
1800                        "a signed integer, group, or field",
1801                        input.receiver.span(),
1802                    ));
1803                }
1804                type_
1805            }
1806            UnaryOperation::Not => {
1807                let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1808                if !matches!(&type_, Type::Err | Type::Boolean | Type::Integer(_)) {
1809                    self.emit_err(TypeCheckerError::type_should_be2(&type_, "a bool or integer", input.span()));
1810                }
1811                type_
1812            }
1813            UnaryOperation::Square => {
1814                let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1815                if type_ == Type::Numeric {
1816                    // We can actually infer to `field` here because only fields can be squared
1817                    type_ = Type::Field;
1818                    self.state.type_table.insert(input.receiver.id(), Type::Field);
1819                } else {
1820                    self.assert_type(&type_, &Type::Field, input.span());
1821                }
1822                type_
1823            }
1824            UnaryOperation::SquareRoot => {
1825                let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1826                if type_ == Type::Numeric {
1827                    // We can actually infer to `field` here because only fields can be square-rooted
1828                    type_ = Type::Field;
1829                    self.state.type_table.insert(input.receiver.id(), Type::Field);
1830                } else {
1831                    self.assert_type(&type_, &Type::Field, input.span());
1832                }
1833                type_
1834            }
1835            UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
1836                let _operand_type = self.visit_expression(&input.receiver, &Some(Type::Group));
1837                self.maybe_assert_type(&Type::Field, destination, input.span());
1838                Type::Field
1839            }
1840        };
1841
1842        self.maybe_assert_type(&ty, destination, input.span());
1843
1844        self.wrap_if_optional(ty, destination)
1845    }
1846
1847    fn visit_unit(&mut self, _input: &UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1848        Type::Unit
1849    }
1850
1851    /* Statements */
1852    fn visit_statement(&mut self, input: &Statement) {
1853        // No statements can follow a return statement.
1854        if self.scope_state.has_return {
1855            self.emit_err(TypeCheckerError::unreachable_code_after_return(input.span()));
1856            return;
1857        }
1858
1859        match input {
1860            Statement::Assert(stmt) => self.visit_assert(stmt),
1861            Statement::Assign(stmt) => self.visit_assign(stmt),
1862            Statement::Block(stmt) => self.visit_block(stmt),
1863            Statement::Conditional(stmt) => self.visit_conditional(stmt),
1864            Statement::Const(stmt) => self.visit_const(stmt),
1865            Statement::Definition(stmt) => self.visit_definition(stmt),
1866            Statement::Expression(stmt) => self.visit_expression_statement(stmt),
1867            Statement::Iteration(stmt) => self.visit_iteration(stmt),
1868            Statement::Return(stmt) => self.visit_return(stmt),
1869        }
1870    }
1871
1872    fn visit_assert(&mut self, input: &AssertStatement) {
1873        match &input.variant {
1874            AssertVariant::Assert(expr) => {
1875                let _type = self.visit_expression(expr, &Some(Type::Boolean));
1876            }
1877            AssertVariant::AssertEq(left, right) | AssertVariant::AssertNeq(left, right) => {
1878                let t1 = self.visit_expression_reject_numeric(left, &None);
1879                let t2 = self.visit_expression_reject_numeric(right, &None);
1880
1881                if t1 != Type::Err && t2 != Type::Err && !t1.eq_user(&t2) {
1882                    let op =
1883                        if matches!(input.variant, AssertVariant::AssertEq(..)) { "assert_eq" } else { "assert_neq" };
1884                    self.emit_err(TypeCheckerError::operation_types_mismatch(op, t1, t2, input.span()));
1885                }
1886            }
1887        }
1888    }
1889
1890    fn visit_assign(&mut self, input: &AssignStatement) {
1891        let (lhs_type, is_storage) = self.visit_expression_assign(&input.place);
1892        let value = &input.value;
1893
1894        if lhs_type == Type::Err {
1895            self.visit_expression(value, &None);
1896            return;
1897        }
1898
1899        if is_storage && !lhs_type.is_vector() && !lhs_type.is_mapping() {
1900            self.check_access_allowed("storage write", true, input.place.span())
1901        }
1902
1903        let expected_rhs_ty = match (is_storage, value.is_none_expr(), &lhs_type) {
1904            (true, false, Type::Optional(OptionalType { inner })) => {
1905                // For storage variables that are being assigned to a value other than `none` where
1906                // the `lhs_type` is an optional, we want the expected type to be the wrapped type
1907                // in that optional. For example:
1908                // ```leo
1909                // storage x: u8; // actually optional
1910                //
1911                // x = 5` // expected type of the RHS is just `u8` (not `u8`?)
1912                // ```
1913                // Note that this means that this would fail with a type mismatch:
1914                // ```leo
1915                // let y: u8? = 5;
1916                // x = y; // Assigning an optional to a storage variable.
1917                // ```
1918                // We should probably eventually support this for completeness, but it add some
1919                // complications that makes it not worth it as this stage.
1920                Some(*inner.clone())
1921            }
1922            _ => {
1923                // Fore everything else, just proceed as normal.
1924                Some(lhs_type)
1925            }
1926        };
1927
1928        self.visit_expression(value, &expected_rhs_ty);
1929    }
1930
1931    fn visit_block(&mut self, input: &Block) {
1932        self.in_scope(input.id, |slf| {
1933            input.statements.iter().for_each(|stmt| slf.visit_statement(stmt));
1934        });
1935    }
1936
1937    fn visit_conditional(&mut self, input: &ConditionalStatement) {
1938        self.visit_expression(&input.condition, &Some(Type::Boolean));
1939
1940        let mut then_block_has_return = false;
1941        let mut otherwise_block_has_return = false;
1942
1943        // Set the `has_return` flag for the then-block.
1944        let previous_has_return = core::mem::replace(&mut self.scope_state.has_return, then_block_has_return);
1945        // Set the `is_conditional` flag.
1946        let previous_is_conditional = core::mem::replace(&mut self.scope_state.is_conditional, true);
1947
1948        // Visit block.
1949        self.in_conditional_scope(|slf| slf.visit_block(&input.then));
1950
1951        // Store the `has_return` flag for the then-block.
1952        then_block_has_return = self.scope_state.has_return;
1953
1954        if let Some(otherwise) = &input.otherwise {
1955            // Set the `has_return` flag for the otherwise-block.
1956            self.scope_state.has_return = otherwise_block_has_return;
1957
1958            match &**otherwise {
1959                Statement::Block(stmt) => {
1960                    // Visit the otherwise-block.
1961                    self.in_conditional_scope(|slf| slf.visit_block(stmt));
1962                }
1963                Statement::Conditional(stmt) => self.visit_conditional(stmt),
1964                _ => unreachable!("Else-case can only be a block or conditional statement."),
1965            }
1966
1967            // Store the `has_return` flag for the otherwise-block.
1968            otherwise_block_has_return = self.scope_state.has_return;
1969        }
1970
1971        // Restore the previous `has_return` flag.
1972        self.scope_state.has_return = previous_has_return || (then_block_has_return && otherwise_block_has_return);
1973        // Restore the previous `is_conditional` flag.
1974        self.scope_state.is_conditional = previous_is_conditional;
1975    }
1976
1977    fn visit_const(&mut self, input: &ConstDeclaration) {
1978        self.visit_type(&input.type_);
1979
1980        // For now, consts that contain optional types are not supported.
1981        // TODO: remove this restriction by supporting const evaluation of optionals including `None`.
1982        if self.contains_optional_type(&input.type_) {
1983            self.emit_err(TypeCheckerError::const_cannot_be_optional(input.span));
1984        }
1985
1986        // Check that the type of the definition is not a unit type, singleton tuple type, or nested tuple type.
1987        match &input.type_ {
1988            // If the type is an empty tuple, return an error.
1989            Type::Unit => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.span)),
1990            // If the type is a singleton tuple, return an error.
1991            Type::Tuple(tuple) => match tuple.length() {
1992                0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
1993                _ => {
1994                    if tuple.elements().iter().any(|type_| matches!(type_, Type::Tuple(_))) {
1995                        self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
1996                    }
1997                }
1998            },
1999            Type::Mapping(_) | Type::Err => unreachable!(
2000                "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
2001            ),
2002            // Otherwise, the type is valid.
2003            _ => (), // Do nothing
2004        }
2005
2006        // Check the expression on the right-hand side.
2007        self.visit_expression(&input.value, &Some(input.type_.clone()));
2008
2009        if self.scope_state.function.is_some() {
2010            // Global consts have already been added to the symbol table, so only
2011            // add this one if it's local.
2012            if let Err(err) = self.state.symbol_table.insert_variable(
2013                self.scope_state.program_name.unwrap(),
2014                &[input.place.name],
2015                VariableSymbol { type_: input.type_.clone(), span: input.place.span, declaration: VariableType::Const },
2016            ) {
2017                self.state.handler.emit_err(err);
2018            }
2019        }
2020    }
2021
2022    fn visit_definition(&mut self, input: &DefinitionStatement) {
2023        // Check that the type annotation of the definition is valid, if provided.
2024        if let Some(ty) = &input.type_ {
2025            self.visit_type(ty);
2026            self.assert_type_is_valid(ty, input.span);
2027        }
2028
2029        // Check that the type of the definition is not a unit type, singleton tuple type, or nested tuple type.
2030        match &input.type_ {
2031            // If the type is a singleton tuple, return an error.
2032            Some(Type::Tuple(tuple)) => match tuple.length() {
2033                0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
2034                _ => {
2035                    for type_ in tuple.elements() {
2036                        if matches!(type_, Type::Tuple(_)) {
2037                            self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
2038                        }
2039                    }
2040                }
2041            },
2042            Some(Type::Mapping(_)) | Some(Type::Err) => unreachable!(
2043                "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
2044            ),
2045            // Otherwise, the type is valid.
2046            _ => (), // Do nothing
2047        }
2048
2049        // Check the expression on the right-hand side. If we could not resolve `Type::Numeric`, then just give up.
2050        // We could do better in the future by potentially looking at consumers of this variable and inferring type
2051        // information from them.
2052        let inferred_type = self.visit_expression_reject_numeric(&input.value, &input.type_);
2053
2054        // If the RHS is a storage vector, error out. Storage vectors cannot be assigned to a variable.
2055        // They can only be accessed directly via `push`, `pop`, etc.
2056        if inferred_type.is_vector() {
2057            self.emit_err(TypeCheckerError::storage_vectors_cannot_be_moved_or_assigned(input.value.span()));
2058        }
2059
2060        // Insert the variables into the symbol table.
2061        match &input.place {
2062            DefinitionPlace::Single(identifier) => {
2063                self.insert_variable(
2064                    Some(inferred_type.clone()),
2065                    identifier,
2066                    // If no type annotation is provided, then just use `inferred_type`.
2067                    input.type_.clone().unwrap_or(inferred_type),
2068                    identifier.span,
2069                );
2070            }
2071            DefinitionPlace::Multiple(identifiers) => {
2072                // Get the tuple type either from `input.type_` or from `inferred_type`.
2073                let tuple_type = match (&input.type_, inferred_type.clone()) {
2074                    (Some(Type::Tuple(tuple_type)), _) => tuple_type.clone(),
2075                    (None, Type::Tuple(tuple_type)) => tuple_type.clone(),
2076                    _ => {
2077                        // This is an error but should have been emitted earlier. Just exit here.
2078                        return;
2079                    }
2080                };
2081
2082                // Ensure the number of identifiers we're defining is the same as the number of tuple elements, as
2083                // indicated by `tuple_type`
2084                if identifiers.len() != tuple_type.length() {
2085                    return self.emit_err(TypeCheckerError::incorrect_num_tuple_elements(
2086                        identifiers.len(),
2087                        tuple_type.length(),
2088                        input.span(),
2089                    ));
2090                }
2091
2092                // Now just insert each tuple element as a separate variable
2093                for (i, identifier) in identifiers.iter().enumerate() {
2094                    let inferred = if let Type::Tuple(inferred_tuple) = &inferred_type {
2095                        inferred_tuple.elements().get(i).cloned().unwrap_or_default()
2096                    } else {
2097                        Type::Err
2098                    };
2099                    self.insert_variable(Some(inferred), identifier, tuple_type.elements()[i].clone(), identifier.span);
2100                }
2101            }
2102        }
2103    }
2104
2105    fn visit_expression_statement(&mut self, input: &ExpressionStatement) {
2106        // Expression statements can only be function calls.
2107        if !matches!(input.expression, Expression::Call(_) | Expression::AssociatedFunction(_) | Expression::Unit(_)) {
2108            self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
2109        } else {
2110            // Check the expression.
2111            self.visit_expression(&input.expression, &None);
2112        }
2113    }
2114
2115    fn visit_iteration(&mut self, input: &IterationStatement) {
2116        // Ensure the type annotation is an integer type
2117        if let Some(ty) = &input.type_ {
2118            self.visit_type(ty);
2119            self.assert_int_type(ty, input.variable.span);
2120        }
2121
2122        // These are the types of the start and end expressions of the iterator range. `visit_expression` will make
2123        // sure they match `input.type_` (i.e. the iterator type annotation) if available.
2124        let start_ty = self.visit_expression(&input.start, &input.type_.clone());
2125        let stop_ty = self.visit_expression(&input.stop, &input.type_.clone());
2126
2127        // Ensure both types are integer types
2128        self.assert_int_type(&start_ty, input.start.span());
2129        self.assert_int_type(&stop_ty, input.stop.span());
2130
2131        if start_ty != stop_ty {
2132            // Emit an error if the types of the range bounds do not match
2133            self.emit_err(TypeCheckerError::range_bounds_type_mismatch(input.start.span() + input.stop.span()));
2134        }
2135
2136        // Now, just set the type of the iterator variable to `start_ty` if `input.type_` is not available. If `stop_ty`
2137        // does not match `start_ty` and `input.type_` is not available, the we just recover with `start_ty` anyways
2138        // and continue.
2139        let iterator_ty = input.type_.clone().unwrap_or(start_ty);
2140        self.state.type_table.insert(input.variable.id(), iterator_ty.clone());
2141
2142        self.in_scope(input.id(), |slf| {
2143            // Add the loop variable to the scope of the loop body.
2144            if let Err(err) = slf.state.symbol_table.insert_variable(
2145                slf.scope_state.program_name.unwrap(),
2146                &[input.variable.name],
2147                VariableSymbol { type_: iterator_ty.clone(), span: input.span(), declaration: VariableType::Const },
2148            ) {
2149                slf.state.handler.emit_err(err);
2150            }
2151
2152            let prior_has_return = core::mem::take(&mut slf.scope_state.has_return);
2153            let prior_has_finalize = core::mem::take(&mut slf.scope_state.has_called_finalize);
2154
2155            slf.visit_block(&input.block);
2156
2157            if slf.scope_state.has_return {
2158                slf.emit_err(TypeCheckerError::loop_body_contains_return(input.span()));
2159            }
2160
2161            if slf.scope_state.has_called_finalize {
2162                slf.emit_err(TypeCheckerError::loop_body_contains_async("function call", input.span()));
2163            }
2164
2165            if slf.scope_state.already_contains_an_async_block {
2166                slf.emit_err(TypeCheckerError::loop_body_contains_async("block expression", input.span()));
2167            }
2168
2169            slf.scope_state.has_return = prior_has_return;
2170            slf.scope_state.has_called_finalize = prior_has_finalize;
2171        });
2172    }
2173
2174    fn visit_return(&mut self, input: &ReturnStatement) {
2175        if self.async_block_id.is_some() {
2176            return self.emit_err(TypeCheckerError::async_block_cannot_return(input.span()));
2177        }
2178
2179        if self.scope_state.is_constructor {
2180            // It must return a unit value; nothing else to check.
2181            if !matches!(input.expression, Expression::Unit(..)) {
2182                self.emit_err(TypeCheckerError::constructor_can_only_return_unit(&input.expression, input.span));
2183            }
2184            return;
2185        }
2186
2187        let caller_name = self.scope_state.function.expect("`self.function` is set every time a function is visited.");
2188        let caller_path =
2189            self.scope_state.module_name.iter().cloned().chain(std::iter::once(caller_name)).collect::<Vec<Symbol>>();
2190
2191        let func_symbol = self
2192            .state
2193            .symbol_table
2194            .lookup_function(&Location::new(self.scope_state.program_name.unwrap(), caller_path.clone()))
2195            .expect("The symbol table creator should already have visited all functions.");
2196
2197        let mut return_type = func_symbol.function.output_type.clone();
2198
2199        if self.scope_state.variant == Some(Variant::AsyncTransition) && self.scope_state.has_called_finalize {
2200            let inferred_future_type = Future(FutureType::new(
2201                if let Some(finalizer) = &func_symbol.finalizer { finalizer.inferred_inputs.clone() } else { vec![] },
2202                Some(Location::new(self.scope_state.program_name.unwrap(), caller_path)),
2203                true,
2204            ));
2205
2206            // Need to modify return type since the function signature is just default future, but the actual return
2207            // type is the fully inferred future of the finalize input type.
2208            let inferred = match return_type.clone() {
2209                Future(_) => inferred_future_type,
2210                Tuple(tuple) => Tuple(TupleType::new(
2211                    tuple
2212                        .elements()
2213                        .iter()
2214                        .map(|t| if matches!(t, Future(_)) { inferred_future_type.clone() } else { t.clone() })
2215                        .collect::<Vec<Type>>(),
2216                )),
2217                _ => {
2218                    return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
2219                }
2220            };
2221
2222            // Check that the explicit type declared in the function output signature matches the inferred type.
2223            return_type = self.assert_and_return_type(inferred, &Some(return_type), input.span());
2224        }
2225
2226        if matches!(input.expression, Expression::Unit(..)) {
2227            // Manually type check rather than using one of the assert functions for a better error message.
2228            if return_type != Type::Unit {
2229                // TODO - This is a bit hackish. We're reusing an existing error, because
2230                // we have too many errors in TypeCheckerError without hitting the recursion
2231                // limit for macros. But the error message to the user should still be pretty clear.
2232                return self.emit_err(TypeCheckerError::missing_return(input.span()));
2233            }
2234        }
2235
2236        self.visit_expression(&input.expression, &Some(return_type));
2237
2238        // Set the `has_return` flag after processing `input.expression` so that we don't error out
2239        // on something like `return async { .. }`.
2240        self.scope_state.has_return = true;
2241    }
2242}