leo_passes/type_checking/
visitor.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 crate::{CompilerState, VariableSymbol, VariableType, type_checking::scope_state::ScopeState};
18
19use super::*;
20
21use leo_ast::*;
22use leo_errors::{TypeCheckerError, TypeCheckerWarning};
23use leo_span::{Span, Symbol};
24
25use indexmap::{IndexMap, IndexSet};
26use std::ops::Deref;
27
28pub struct TypeCheckingVisitor<'a> {
29    pub state: &'a mut CompilerState,
30    /// The state of the current scope being traversed.
31    pub scope_state: ScopeState,
32    /// Mapping from async function stub name to the inferred input types.
33    pub async_function_input_types: IndexMap<Location, Vec<Type>>,
34    /// Mapping from async function name to the names of async transition callers.
35    pub async_function_callers: IndexMap<Location, IndexSet<Location>>,
36    /// The set of used composites.
37    pub used_structs: IndexSet<Vec<Symbol>>,
38    /// So we can check if we exceed limits on array size, number of mappings, or number of functions.
39    pub limits: TypeCheckingInput,
40    /// For detecting the error `TypeCheckerError::async_cannot_assign_outside_conditional`.
41    pub conditional_scopes: Vec<IndexSet<Symbol>>,
42    /// If we're inside an async block, this is the node ID of the contained `Block`. Otherwise, this is `None`.
43    pub async_block_id: Option<NodeID>,
44}
45
46impl TypeCheckingVisitor<'_> {
47    pub fn in_scope<T>(&mut self, id: NodeID, func: impl FnOnce(&mut Self) -> T) -> T {
48        self.state.symbol_table.enter_scope(Some(id));
49        let result = func(self);
50        self.state.symbol_table.enter_parent();
51        result
52    }
53
54    pub fn in_conditional_scope<T>(&mut self, func: impl FnOnce(&mut Self) -> T) -> T {
55        self.conditional_scopes.push(Default::default());
56        let result = func(self);
57        self.conditional_scopes.pop();
58        result
59    }
60
61    pub fn insert_symbol_conditional_scope(&mut self, symbol: Symbol) {
62        self.conditional_scopes.last_mut().expect("A conditional scope must be present.").insert(symbol);
63    }
64
65    pub fn symbol_in_conditional_scope(&mut self, symbol: Symbol) -> bool {
66        self.conditional_scopes.last().map(|set| set.contains(&symbol)).unwrap_or(false)
67    }
68
69    /// Emits a type checker error.
70    pub fn emit_err(&self, err: TypeCheckerError) {
71        self.state.handler.emit_err(err);
72    }
73
74    /// Emits a type checker warning
75    pub fn emit_warning(&mut self, warning: TypeCheckerWarning) {
76        if self.state.warnings.insert(warning.clone().into()) {
77            self.state.handler.emit_warning(warning.into());
78        }
79    }
80
81    /// Emits an error if the two given types are not equal.
82    pub fn check_eq_types(&self, t1: &Option<Type>, t2: &Option<Type>, span: Span) {
83        match (t1, t2) {
84            (Some(t1), Some(t2)) if !t1.eq_flat_relaxed(t2) => {
85                self.emit_err(TypeCheckerError::type_should_be(t1, t2, span))
86            }
87            (Some(type_), None) | (None, Some(type_)) => {
88                self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
89            }
90            _ => {}
91        }
92    }
93
94    /// Use this method when you know the actual type.
95    /// Emits an error to the handler if the `actual` type is not equal to the `expected` type.
96    pub fn assert_and_return_type(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
97        // If expected is `Type::Err`, we don't want to actually report a redundant error.
98        if expected.is_some() && !matches!(expected, Some(Type::Err)) {
99            self.check_eq_types(&Some(actual.clone()), expected, span);
100        }
101        actual
102    }
103
104    pub fn maybe_assert_type(&mut self, actual: &Type, expected: &Option<Type>, span: Span) {
105        if let Some(expected) = expected {
106            self.assert_type(actual, expected, span);
107        }
108    }
109
110    pub fn assert_type(&mut self, actual: &Type, expected: &Type, span: Span) {
111        if actual != &Type::Err && !actual.can_coerce_to(expected) {
112            // If `actual` is Err, we will have already reported an error.
113            self.emit_err(TypeCheckerError::type_should_be2(actual, format!("type `{expected}`"), span));
114        }
115    }
116
117    /// Unwraps an optional type to its inner type for use with operands.
118    /// If the expected type is `T?`, returns `Some(T)`. Otherwise returns the type as-is.
119    pub fn unwrap_optional_type(&self, expected: &Option<Type>) -> Option<Type> {
120        match expected {
121            Some(Type::Optional(opt_type)) => Some(*opt_type.inner.clone()),
122            other => other.clone(),
123        }
124    }
125
126    /// Wraps a type in Optional if the destination type is Optional.
127    /// If destination is `T?` and actual is `T`, returns `T?`. Otherwise returns actual as-is.
128    pub fn wrap_if_optional(&self, actual: Type, destination: &Option<Type>) -> Type {
129        match (actual, destination) {
130            // if destination is Optional<T> and actual is T (not already Optional), wrap it
131            (actual_type, Some(Type::Optional(opt_type))) if !matches!(actual_type, Type::Optional(_)) => {
132                // only wrap if the inner type matches
133                if actual_type.can_coerce_to(&opt_type.inner) {
134                    Type::Optional(OptionalType { inner: Box::new(actual_type) })
135                } else {
136                    actual_type
137                }
138            }
139            (actual_type, _) => actual_type,
140        }
141    }
142
143    pub fn assert_int_type(&self, type_: &Type, span: Span) {
144        if !matches!(type_, Type::Err | Type::Integer(_)) {
145            self.emit_err(TypeCheckerError::type_should_be2(type_, "an integer", span));
146        }
147    }
148
149    pub fn assert_unsigned_type(&self, type_: &Type, span: Span) {
150        if !matches!(
151            type_,
152            Type::Err
153                | Type::Integer(IntegerType::U8)
154                | Type::Integer(IntegerType::U16)
155                | Type::Integer(IntegerType::U32)
156                | Type::Integer(IntegerType::U64)
157                | Type::Integer(IntegerType::U128)
158        ) {
159            self.emit_err(TypeCheckerError::type_should_be2(type_, "an unsigned integer", span));
160        }
161    }
162
163    pub fn assert_bool_int_type(&self, type_: &Type, span: Span) {
164        if !matches!(
165            type_,
166            Type::Err
167                | Type::Boolean
168                | Type::Integer(IntegerType::U8)
169                | Type::Integer(IntegerType::U16)
170                | Type::Integer(IntegerType::U32)
171                | Type::Integer(IntegerType::U64)
172                | Type::Integer(IntegerType::U128)
173                | Type::Integer(IntegerType::I8)
174                | Type::Integer(IntegerType::I16)
175                | Type::Integer(IntegerType::I32)
176                | Type::Integer(IntegerType::I64)
177                | Type::Integer(IntegerType::I128)
178        ) {
179            self.emit_err(TypeCheckerError::type_should_be2(type_, "a bool or integer", span));
180        }
181    }
182
183    pub fn assert_field_int_type(&self, type_: &Type, span: Span) {
184        if !matches!(
185            type_,
186            Type::Err
187                | Type::Field
188                | Type::Integer(IntegerType::U8)
189                | Type::Integer(IntegerType::U16)
190                | Type::Integer(IntegerType::U32)
191                | Type::Integer(IntegerType::U64)
192                | Type::Integer(IntegerType::U128)
193                | Type::Integer(IntegerType::I8)
194                | Type::Integer(IntegerType::I16)
195                | Type::Integer(IntegerType::I32)
196                | Type::Integer(IntegerType::I64)
197                | Type::Integer(IntegerType::I128)
198        ) {
199            self.emit_err(TypeCheckerError::type_should_be2(type_, "a field or integer", span));
200        }
201    }
202
203    pub fn assert_field_group_int_type(&self, type_: &Type, span: Span) {
204        if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Integer(_)) {
205            self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, group, or integer", span));
206        }
207    }
208
209    /// Type checks the inputs to an associated constant and returns the expected output type.
210    pub fn get_core_constant(&self, type_: &Type, constant: &Identifier) -> Option<CoreConstant> {
211        if let Type::Identifier(ident) = type_ {
212            // Lookup core constant
213            match CoreConstant::from_symbols(ident.name, constant.name) {
214                None => {
215                    // Not a core constant.
216                    self.emit_err(TypeCheckerError::invalid_core_constant(ident.name, constant.name, ident.span()));
217                }
218                Some(core_constant) => return Some(core_constant),
219            }
220        }
221        None
222    }
223
224    /// Emits an error if the `struct` is not a core library struct.
225    /// Emits an error if the `function` is not supported by the struct.
226    pub fn get_core_function_call(&self, struct_: &Identifier, function: &Identifier) -> Option<CoreFunction> {
227        // Lookup core struct
228        match CoreFunction::from_symbols(struct_.name, function.name) {
229            None => {
230                // Not a core library struct.
231                self.emit_err(TypeCheckerError::invalid_core_function(struct_.name, function.name, struct_.span()));
232                None
233            }
234            Some(core_instruction) => Some(core_instruction),
235        }
236    }
237
238    /// Type checks the inputs to a core function call and returns the expected output type.
239    /// Emits an error if the correct number of arguments are not provided.
240    /// Emits an error if the arguments are not of the correct type.
241    pub fn check_core_function_call(
242        &mut self,
243        core_function: CoreFunction,
244        arguments: &[(Type, &Expression)],
245        function_span: Span,
246    ) -> Type {
247        // Check that the number of arguments is correct.
248        if arguments.len() != core_function.num_args() {
249            self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
250                core_function.num_args(),
251                arguments.len(),
252                function_span,
253            ));
254            return Type::Err;
255        }
256
257        let assert_not_mapping_tuple_unit = |type_: &Type, span: Span| {
258            if matches!(type_, Type::Mapping(_) | Type::Tuple(_) | Type::Unit) {
259                self.emit_err(TypeCheckerError::type_should_be2(type_, "anything but a mapping, tuple, or unit", span));
260            }
261        };
262
263        // Make sure the input is no bigger than 64 bits.
264        // Due to overhead in the bitwise representations of types in SnarkVM, 64 bit integers
265        // input more than 64 bits to a hash function, as do all structs and arrays.
266        let assert_pedersen_64_bit_input = |type_: &Type, span: Span| {
267            if !matches!(
268                type_,
269                Type::Integer(IntegerType::U8)
270                    | Type::Integer(IntegerType::U16)
271                    | Type::Integer(IntegerType::U32)
272                    | Type::Integer(IntegerType::I8)
273                    | Type::Integer(IntegerType::I16)
274                    | Type::Integer(IntegerType::I32)
275                    | Type::Boolean
276                    | Type::Err
277            ) {
278                self.emit_err(TypeCheckerError::type_should_be2(
279                    type_,
280                    "an integer of less than 64 bits or a bool",
281                    span,
282                ));
283            }
284        };
285
286        // Make sure the input is no bigger than 128 bits.
287        //
288        // Due to overhead in the bitwise representations of types in SnarkVM, 128 bit integers
289        // input more than 128 bits to a hash function, as do most structs and arrays. We could
290        // actually allow arrays with a single element of type smaller than 64 bits, but it
291        // seems most understandable to the user to simply disallow composite types entirely.
292        let assert_pedersen_128_bit_input = |type_: &Type, span: Span| {
293            if !matches!(
294                type_,
295                Type::Integer(IntegerType::U8)
296                    | Type::Integer(IntegerType::U16)
297                    | Type::Integer(IntegerType::U32)
298                    | Type::Integer(IntegerType::U64)
299                    | Type::Integer(IntegerType::I8)
300                    | Type::Integer(IntegerType::I16)
301                    | Type::Integer(IntegerType::I32)
302                    | Type::Integer(IntegerType::I64)
303                    | Type::Boolean
304                    | Type::Err
305            ) {
306                self.emit_err(TypeCheckerError::type_should_be2(
307                    type_,
308                    "an integer of less than 128 bits or a bool",
309                    span,
310                ));
311            }
312        };
313
314        // Define a regex to match valid program IDs.
315        let program_id_regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z0-9_]*\.aleo$").unwrap();
316
317        // Check that the arguments are of the correct type.
318        match core_function {
319            CoreFunction::BHP256CommitToAddress
320            | CoreFunction::BHP512CommitToAddress
321            | CoreFunction::BHP768CommitToAddress
322            | CoreFunction::BHP1024CommitToAddress => {
323                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
324                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
325                Type::Address
326            }
327            CoreFunction::BHP256CommitToField
328            | CoreFunction::BHP512CommitToField
329            | CoreFunction::BHP768CommitToField
330            | CoreFunction::BHP1024CommitToField => {
331                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
332                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
333                Type::Field
334            }
335            CoreFunction::BHP256CommitToGroup
336            | CoreFunction::BHP512CommitToGroup
337            | CoreFunction::BHP768CommitToGroup
338            | CoreFunction::BHP1024CommitToGroup => {
339                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
340                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
341                Type::Group
342            }
343            CoreFunction::BHP256HashToAddress
344            | CoreFunction::BHP512HashToAddress
345            | CoreFunction::BHP768HashToAddress
346            | CoreFunction::BHP1024HashToAddress
347            | CoreFunction::Keccak256HashToAddress
348            | CoreFunction::Keccak384HashToAddress
349            | CoreFunction::Keccak512HashToAddress
350            | CoreFunction::Poseidon2HashToAddress
351            | CoreFunction::Poseidon4HashToAddress
352            | CoreFunction::Poseidon8HashToAddress
353            | CoreFunction::SHA3_256HashToAddress
354            | CoreFunction::SHA3_384HashToAddress
355            | CoreFunction::SHA3_512HashToAddress => {
356                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
357                Type::Address
358            }
359            CoreFunction::BHP256HashToField
360            | CoreFunction::BHP512HashToField
361            | CoreFunction::BHP768HashToField
362            | CoreFunction::BHP1024HashToField
363            | CoreFunction::Keccak256HashToField
364            | CoreFunction::Keccak384HashToField
365            | CoreFunction::Keccak512HashToField
366            | CoreFunction::Poseidon2HashToField
367            | CoreFunction::Poseidon4HashToField
368            | CoreFunction::Poseidon8HashToField
369            | CoreFunction::SHA3_256HashToField
370            | CoreFunction::SHA3_384HashToField
371            | CoreFunction::SHA3_512HashToField => {
372                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
373                Type::Field
374            }
375            CoreFunction::BHP256HashToGroup
376            | CoreFunction::BHP512HashToGroup
377            | CoreFunction::BHP768HashToGroup
378            | CoreFunction::BHP1024HashToGroup
379            | CoreFunction::Keccak256HashToGroup
380            | CoreFunction::Keccak384HashToGroup
381            | CoreFunction::Keccak512HashToGroup
382            | CoreFunction::Poseidon2HashToGroup
383            | CoreFunction::Poseidon4HashToGroup
384            | CoreFunction::Poseidon8HashToGroup
385            | CoreFunction::SHA3_256HashToGroup
386            | CoreFunction::SHA3_384HashToGroup
387            | CoreFunction::SHA3_512HashToGroup => {
388                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
389                Type::Group
390            }
391            CoreFunction::BHP256HashToI8
392            | CoreFunction::BHP512HashToI8
393            | CoreFunction::BHP768HashToI8
394            | CoreFunction::BHP1024HashToI8
395            | CoreFunction::Keccak256HashToI8
396            | CoreFunction::Keccak384HashToI8
397            | CoreFunction::Keccak512HashToI8
398            | CoreFunction::Poseidon2HashToI8
399            | CoreFunction::Poseidon4HashToI8
400            | CoreFunction::Poseidon8HashToI8
401            | CoreFunction::SHA3_256HashToI8
402            | CoreFunction::SHA3_384HashToI8
403            | CoreFunction::SHA3_512HashToI8 => {
404                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
405                Type::Integer(IntegerType::I8)
406            }
407            CoreFunction::BHP256HashToI16
408            | CoreFunction::BHP512HashToI16
409            | CoreFunction::BHP768HashToI16
410            | CoreFunction::BHP1024HashToI16
411            | CoreFunction::Keccak256HashToI16
412            | CoreFunction::Keccak384HashToI16
413            | CoreFunction::Keccak512HashToI16
414            | CoreFunction::Poseidon2HashToI16
415            | CoreFunction::Poseidon4HashToI16
416            | CoreFunction::Poseidon8HashToI16
417            | CoreFunction::SHA3_256HashToI16
418            | CoreFunction::SHA3_384HashToI16
419            | CoreFunction::SHA3_512HashToI16 => {
420                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
421                Type::Integer(IntegerType::I16)
422            }
423            CoreFunction::BHP256HashToI32
424            | CoreFunction::BHP512HashToI32
425            | CoreFunction::BHP768HashToI32
426            | CoreFunction::BHP1024HashToI32
427            | CoreFunction::Keccak256HashToI32
428            | CoreFunction::Keccak384HashToI32
429            | CoreFunction::Keccak512HashToI32
430            | CoreFunction::Poseidon2HashToI32
431            | CoreFunction::Poseidon4HashToI32
432            | CoreFunction::Poseidon8HashToI32
433            | CoreFunction::SHA3_256HashToI32
434            | CoreFunction::SHA3_384HashToI32
435            | CoreFunction::SHA3_512HashToI32 => {
436                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
437                Type::Integer(IntegerType::I32)
438            }
439            CoreFunction::BHP256HashToI64
440            | CoreFunction::BHP512HashToI64
441            | CoreFunction::BHP768HashToI64
442            | CoreFunction::BHP1024HashToI64
443            | CoreFunction::Keccak256HashToI64
444            | CoreFunction::Keccak384HashToI64
445            | CoreFunction::Keccak512HashToI64
446            | CoreFunction::Poseidon2HashToI64
447            | CoreFunction::Poseidon4HashToI64
448            | CoreFunction::Poseidon8HashToI64
449            | CoreFunction::SHA3_256HashToI64
450            | CoreFunction::SHA3_384HashToI64
451            | CoreFunction::SHA3_512HashToI64 => {
452                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
453                Type::Integer(IntegerType::I64)
454            }
455            CoreFunction::BHP256HashToI128
456            | CoreFunction::BHP512HashToI128
457            | CoreFunction::BHP768HashToI128
458            | CoreFunction::BHP1024HashToI128
459            | CoreFunction::Keccak256HashToI128
460            | CoreFunction::Keccak384HashToI128
461            | CoreFunction::Keccak512HashToI128
462            | CoreFunction::Poseidon2HashToI128
463            | CoreFunction::Poseidon4HashToI128
464            | CoreFunction::Poseidon8HashToI128
465            | CoreFunction::SHA3_256HashToI128
466            | CoreFunction::SHA3_384HashToI128
467            | CoreFunction::SHA3_512HashToI128 => {
468                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
469                Type::Integer(IntegerType::I128)
470            }
471            CoreFunction::BHP256HashToU8
472            | CoreFunction::BHP512HashToU8
473            | CoreFunction::BHP768HashToU8
474            | CoreFunction::BHP1024HashToU8
475            | CoreFunction::Keccak256HashToU8
476            | CoreFunction::Keccak384HashToU8
477            | CoreFunction::Keccak512HashToU8
478            | CoreFunction::Poseidon2HashToU8
479            | CoreFunction::Poseidon4HashToU8
480            | CoreFunction::Poseidon8HashToU8
481            | CoreFunction::SHA3_256HashToU8
482            | CoreFunction::SHA3_384HashToU8
483            | CoreFunction::SHA3_512HashToU8 => {
484                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
485                Type::Integer(IntegerType::U8)
486            }
487            CoreFunction::BHP256HashToU16
488            | CoreFunction::BHP512HashToU16
489            | CoreFunction::BHP768HashToU16
490            | CoreFunction::BHP1024HashToU16
491            | CoreFunction::Keccak256HashToU16
492            | CoreFunction::Keccak384HashToU16
493            | CoreFunction::Keccak512HashToU16
494            | CoreFunction::Poseidon2HashToU16
495            | CoreFunction::Poseidon4HashToU16
496            | CoreFunction::Poseidon8HashToU16
497            | CoreFunction::SHA3_256HashToU16
498            | CoreFunction::SHA3_384HashToU16
499            | CoreFunction::SHA3_512HashToU16 => {
500                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
501                Type::Integer(IntegerType::U16)
502            }
503            CoreFunction::BHP256HashToU32
504            | CoreFunction::BHP512HashToU32
505            | CoreFunction::BHP768HashToU32
506            | CoreFunction::BHP1024HashToU32
507            | CoreFunction::Keccak256HashToU32
508            | CoreFunction::Keccak384HashToU32
509            | CoreFunction::Keccak512HashToU32
510            | CoreFunction::Poseidon2HashToU32
511            | CoreFunction::Poseidon4HashToU32
512            | CoreFunction::Poseidon8HashToU32
513            | CoreFunction::SHA3_256HashToU32
514            | CoreFunction::SHA3_384HashToU32
515            | CoreFunction::SHA3_512HashToU32 => {
516                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
517                Type::Integer(IntegerType::U32)
518            }
519            CoreFunction::BHP256HashToU64
520            | CoreFunction::BHP512HashToU64
521            | CoreFunction::BHP768HashToU64
522            | CoreFunction::BHP1024HashToU64
523            | CoreFunction::Keccak256HashToU64
524            | CoreFunction::Keccak384HashToU64
525            | CoreFunction::Keccak512HashToU64
526            | CoreFunction::Poseidon2HashToU64
527            | CoreFunction::Poseidon4HashToU64
528            | CoreFunction::Poseidon8HashToU64
529            | CoreFunction::SHA3_256HashToU64
530            | CoreFunction::SHA3_384HashToU64
531            | CoreFunction::SHA3_512HashToU64 => {
532                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
533                Type::Integer(IntegerType::U64)
534            }
535            CoreFunction::BHP256HashToU128
536            | CoreFunction::BHP512HashToU128
537            | CoreFunction::BHP768HashToU128
538            | CoreFunction::BHP1024HashToU128
539            | CoreFunction::Keccak256HashToU128
540            | CoreFunction::Keccak384HashToU128
541            | CoreFunction::Keccak512HashToU128
542            | CoreFunction::Poseidon2HashToU128
543            | CoreFunction::Poseidon4HashToU128
544            | CoreFunction::Poseidon8HashToU128
545            | CoreFunction::SHA3_256HashToU128
546            | CoreFunction::SHA3_384HashToU128
547            | CoreFunction::SHA3_512HashToU128 => {
548                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
549                Type::Integer(IntegerType::U128)
550            }
551            CoreFunction::BHP256HashToScalar
552            | CoreFunction::BHP512HashToScalar
553            | CoreFunction::BHP768HashToScalar
554            | CoreFunction::BHP1024HashToScalar
555            | CoreFunction::Keccak256HashToScalar
556            | CoreFunction::Keccak384HashToScalar
557            | CoreFunction::Keccak512HashToScalar
558            | CoreFunction::Poseidon2HashToScalar
559            | CoreFunction::Poseidon4HashToScalar
560            | CoreFunction::Poseidon8HashToScalar
561            | CoreFunction::SHA3_256HashToScalar
562            | CoreFunction::SHA3_384HashToScalar
563            | CoreFunction::SHA3_512HashToScalar => {
564                assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
565                Type::Scalar
566            }
567            CoreFunction::Pedersen64CommitToAddress => {
568                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
569                // Check that the second argument is a scalar.
570                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
571                Type::Address
572            }
573            CoreFunction::Pedersen64CommitToField => {
574                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
575                // Check that the second argument is a scalar.
576                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
577                Type::Field
578            }
579            CoreFunction::Pedersen64CommitToGroup => {
580                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
581                // Check that the second argument is a scalar.
582                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
583                Type::Group
584            }
585            CoreFunction::Pedersen64HashToAddress => {
586                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
587                Type::Address
588            }
589            CoreFunction::Pedersen64HashToField => {
590                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
591                Type::Field
592            }
593            CoreFunction::Pedersen64HashToGroup => {
594                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
595                Type::Group
596            }
597            CoreFunction::Pedersen64HashToI8 => {
598                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
599                Type::Integer(IntegerType::I8)
600            }
601            CoreFunction::Pedersen64HashToI16 => {
602                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
603                Type::Integer(IntegerType::I16)
604            }
605            CoreFunction::Pedersen64HashToI32 => {
606                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
607                Type::Integer(IntegerType::I32)
608            }
609            CoreFunction::Pedersen64HashToI64 => {
610                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
611                Type::Integer(IntegerType::I64)
612            }
613            CoreFunction::Pedersen64HashToI128 => {
614                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
615                Type::Integer(IntegerType::I128)
616            }
617            CoreFunction::Pedersen64HashToU8 => {
618                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
619                Type::Integer(IntegerType::U8)
620            }
621            CoreFunction::Pedersen64HashToU16 => {
622                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
623                Type::Integer(IntegerType::U16)
624            }
625            CoreFunction::Pedersen64HashToU32 => {
626                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
627                Type::Integer(IntegerType::U32)
628            }
629            CoreFunction::Pedersen64HashToU64 => {
630                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
631                Type::Integer(IntegerType::U64)
632            }
633            CoreFunction::Pedersen64HashToU128 => {
634                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
635                Type::Integer(IntegerType::U128)
636            }
637            CoreFunction::Pedersen64HashToScalar => {
638                assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
639                Type::Scalar
640            }
641            CoreFunction::Pedersen128CommitToAddress => {
642                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
643                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
644                Type::Address
645            }
646            CoreFunction::Pedersen128CommitToField => {
647                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
648                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
649                Type::Field
650            }
651            CoreFunction::Pedersen128CommitToGroup => {
652                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
653                self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
654                Type::Group
655            }
656            CoreFunction::Pedersen128HashToAddress => {
657                // Check that the first argument is not a mapping, tuple, err, unit type, or integer over 64 bits.
658                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
659                Type::Address
660            }
661            CoreFunction::Pedersen128HashToField => {
662                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
663                Type::Field
664            }
665            CoreFunction::Pedersen128HashToGroup => {
666                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
667                Type::Group
668            }
669            CoreFunction::Pedersen128HashToI8 => {
670                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
671                Type::Integer(IntegerType::I8)
672            }
673            CoreFunction::Pedersen128HashToI16 => {
674                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
675                Type::Integer(IntegerType::I16)
676            }
677            CoreFunction::Pedersen128HashToI32 => {
678                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
679                Type::Integer(IntegerType::I32)
680            }
681            CoreFunction::Pedersen128HashToI64 => {
682                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
683                Type::Integer(IntegerType::I64)
684            }
685            CoreFunction::Pedersen128HashToI128 => {
686                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
687                Type::Integer(IntegerType::I128)
688            }
689            CoreFunction::Pedersen128HashToU8 => {
690                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
691                Type::Integer(IntegerType::U8)
692            }
693            CoreFunction::Pedersen128HashToU16 => {
694                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
695                Type::Integer(IntegerType::U16)
696            }
697            CoreFunction::Pedersen128HashToU32 => {
698                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
699                Type::Integer(IntegerType::U32)
700            }
701            CoreFunction::Pedersen128HashToU64 => {
702                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
703                Type::Integer(IntegerType::U64)
704            }
705            CoreFunction::Pedersen128HashToU128 => {
706                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
707                Type::Integer(IntegerType::U128)
708            }
709            CoreFunction::Pedersen128HashToScalar => {
710                assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
711                Type::Scalar
712            }
713            CoreFunction::MappingGet => {
714                // Check that the operation is invoked in a `finalize` block.
715                self.check_access_allowed("Mapping::get", true, function_span);
716                // Check that the first argument is a mapping.
717                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
718                let Type::Mapping(mapping_type) = &arguments[0].0 else {
719                    // We will have already handled the error in the assertion.
720                    return Type::Err;
721                };
722
723                self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
724
725                mapping_type.value.deref().clone()
726            }
727            CoreFunction::MappingGetOrUse => {
728                // Check that the operation is invoked in a `finalize` block.
729                self.check_access_allowed("Mapping::get_or_use", true, function_span);
730                // Check that the first argument is a mapping.
731                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
732
733                let Type::Mapping(mapping_type) = &arguments[0].0 else {
734                    // We will have already handled the error in the assertion.
735                    return Type::Err;
736                };
737
738                // Check that the second argument matches the key type of the mapping.
739                self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
740                // Check that the third argument matches the value type of the mapping.
741                self.assert_type(&arguments[2].0, &mapping_type.value, arguments[2].1.span());
742
743                mapping_type.value.deref().clone()
744            }
745            CoreFunction::MappingSet => {
746                // Check that the operation is invoked in a `finalize` block.
747                self.check_access_allowed("Mapping::set", true, function_span);
748                // Check that the first argument is a mapping.
749                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
750
751                let Type::Mapping(mapping_type) = &arguments[0].0 else {
752                    // We will have already handled the error in the assertion.
753                    return Type::Err;
754                };
755
756                // Check that the second argument matches the key type of the mapping.
757                self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
758                // Check that the third argument matches the value type of the mapping.
759                self.assert_type(&arguments[2].0, &mapping_type.value, arguments[2].1.span());
760
761                Type::Unit
762            }
763            CoreFunction::MappingRemove => {
764                // Check that the operation is invoked in a `finalize` block.
765                self.check_access_allowed("Mapping::remove", true, function_span);
766                // Check that the first argument is a mapping.
767                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
768
769                let Type::Mapping(mapping_type) = &arguments[0].0 else {
770                    // We will have already handled the error in the assertion.
771                    return Type::Err;
772                };
773
774                // Cannot modify external mappings.
775                if mapping_type.program != self.scope_state.program_name.unwrap() {
776                    self.state
777                        .handler
778                        .emit_err(TypeCheckerError::cannot_modify_external_mapping("remove", function_span));
779                }
780
781                // Check that the second argument matches the key type of the mapping.
782                self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
783
784                Type::Unit
785            }
786            CoreFunction::MappingContains => {
787                // Check that the operation is invoked in a `finalize` block.
788                self.check_access_allowed("Mapping::contains", true, function_span);
789                // Check that the first argument is a mapping.
790                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
791
792                let Type::Mapping(mapping_type) = &arguments[0].0 else {
793                    // We will have already handled the error in the assertion.
794                    return Type::Err;
795                };
796
797                // Check that the second argument matches the key type of the mapping.
798                self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
799
800                Type::Boolean
801            }
802            CoreFunction::OptionalUnwrap => {
803                // Check that the first argument is an optional.
804                self.assert_optional_type(&arguments[0].0, arguments[0].1.span());
805
806                match &arguments[0].0 {
807                    Type::Optional(opt) => opt.inner.deref().clone(),
808                    _ => Type::Err,
809                }
810            }
811            CoreFunction::OptionalUnwrapOr => {
812                unreachable!("we should have handled separately outside `check_core_function_call`.")
813            }
814            CoreFunction::GroupToXCoordinate | CoreFunction::GroupToYCoordinate => {
815                // Check that the first argument is a group.
816                self.assert_type(&arguments[0].0, &Type::Group, arguments[0].1.span());
817                Type::Field
818            }
819            CoreFunction::ChaChaRandAddress => Type::Address,
820            CoreFunction::ChaChaRandBool => Type::Boolean,
821            CoreFunction::ChaChaRandField => Type::Field,
822            CoreFunction::ChaChaRandGroup => Type::Group,
823            CoreFunction::ChaChaRandI8 => Type::Integer(IntegerType::I8),
824            CoreFunction::ChaChaRandI16 => Type::Integer(IntegerType::I16),
825            CoreFunction::ChaChaRandI32 => Type::Integer(IntegerType::I32),
826            CoreFunction::ChaChaRandI64 => Type::Integer(IntegerType::I64),
827            CoreFunction::ChaChaRandI128 => Type::Integer(IntegerType::I128),
828            CoreFunction::ChaChaRandScalar => Type::Scalar,
829            CoreFunction::ChaChaRandU8 => Type::Integer(IntegerType::U8),
830            CoreFunction::ChaChaRandU16 => Type::Integer(IntegerType::U16),
831            CoreFunction::ChaChaRandU32 => Type::Integer(IntegerType::U32),
832            CoreFunction::ChaChaRandU64 => Type::Integer(IntegerType::U64),
833            CoreFunction::ChaChaRandU128 => Type::Integer(IntegerType::U128),
834            CoreFunction::SignatureVerify => {
835                // Check that the third argument is not a mapping nor a tuple. We have to do this
836                // before the other checks below to appease the borrow checker
837                assert_not_mapping_tuple_unit(&arguments[2].0, arguments[2].1.span());
838
839                // Check that the first argument is a signature.
840                self.assert_type(&arguments[0].0, &Type::Signature, arguments[0].1.span());
841                // Check that the second argument is an address.
842                self.assert_type(&arguments[1].0, &Type::Address, arguments[1].1.span());
843                Type::Boolean
844            }
845            CoreFunction::FutureAwait => Type::Unit,
846            CoreFunction::ProgramChecksum => {
847                // Get the argument type, expression, and span.
848                let (type_, expression) = &arguments[0];
849                let span = expression.span();
850                // Check that the expression is a program ID.
851                match expression {
852                    Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
853                        if program_id_regex.is_match(s) => {}
854                    _ => {
855                        self.emit_err(TypeCheckerError::custom(
856                            "`Program::checksum` must be called on a program ID, e.g. `foo.aleo`",
857                            span,
858                        ));
859                    }
860                }
861                // Verify that the argument is a string.
862                self.assert_type(type_, &Type::Address, span);
863                // Return the type.
864                Type::Array(ArrayType::new(
865                    Type::Integer(IntegerType::U8),
866                    Expression::Literal(Literal::integer(
867                        IntegerType::U8,
868                        "32".to_string(),
869                        Default::default(),
870                        Default::default(),
871                    )),
872                ))
873            }
874            CoreFunction::ProgramEdition => {
875                // Get the argument type, expression, and span.
876                let (type_, expression) = &arguments[0];
877                let span = expression.span();
878                // Check that the expression is a member access.
879                match expression {
880                    Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
881                        if program_id_regex.is_match(s) => {}
882                    _ => {
883                        self.emit_err(TypeCheckerError::custom(
884                            "`Program::edition` must be called on a program ID, e.g. `foo.aleo`",
885                            span,
886                        ));
887                    }
888                }
889                // Verify that the argument is a string.
890                self.assert_type(type_, &Type::Address, span);
891                // Return the type.
892                Type::Integer(IntegerType::U16)
893            }
894            CoreFunction::ProgramOwner => {
895                // Get the argument type, expression, and span.
896                let (type_, expression) = &arguments[0];
897                let span = expression.span();
898                // Check that the expression is a member access.
899                match expression {
900                    Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
901                        if program_id_regex.is_match(s) => {}
902                    _ => {
903                        self.emit_err(TypeCheckerError::custom(
904                            "`Program::program_owner` must be called on a program ID, e.g. `foo.aleo`",
905                            span,
906                        ));
907                    }
908                }
909                // Verify that the argument is a string.
910                self.assert_type(type_, &Type::Address, span);
911                // Return the type.
912                Type::Address
913            }
914            CoreFunction::CheatCodePrintMapping => {
915                self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
916                Type::Unit
917            }
918            CoreFunction::CheatCodeSetBlockHeight => {
919                self.assert_type(&arguments[0].0, &Type::Integer(IntegerType::U32), arguments[0].1.span());
920                Type::Unit
921            }
922        }
923    }
924
925    /// Emits an error if the struct member is a record type.
926    pub fn assert_member_is_not_record(&mut self, span: Span, parent: Symbol, type_: &Type) {
927        match type_ {
928            Type::Composite(struct_)
929                if self
930                    .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
931                    .is_some_and(|struct_| struct_.is_record) =>
932            {
933                self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(
934                    parent,
935                    struct_.path.clone(),
936                    span,
937                ))
938            }
939            Type::Tuple(tuple_type) => {
940                for type_ in tuple_type.elements().iter() {
941                    self.assert_member_is_not_record(span, parent, type_)
942                }
943            }
944            _ => {} // Do nothing.
945        }
946    }
947
948    /// Emits an error if the type or its constituent types is not valid.
949    pub fn assert_type_is_valid(&mut self, type_: &Type, span: Span) {
950        match type_ {
951            // Unit types may only appear as the return type of a function.
952            Type::Unit => {
953                self.emit_err(TypeCheckerError::unit_type_only_return(span));
954            }
955            // String types are temporarily disabled.
956            Type::String => {
957                self.emit_err(TypeCheckerError::strings_are_not_supported(span));
958            }
959            // Check that named composite type has been defined.
960            Type::Composite(struct_)
961                if self
962                    .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
963                    .is_none() =>
964            {
965                self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), span));
966            }
967            // Check that the constituent types of the tuple are valid.
968            Type::Tuple(tuple_type) => {
969                for type_ in tuple_type.elements().iter() {
970                    self.assert_type_is_valid(type_, span);
971                }
972            }
973            // Check that the constituent types of mapping are valid.
974            Type::Mapping(mapping_type) => {
975                self.assert_type_is_valid(&mapping_type.key, span);
976                self.assert_type_is_valid(&mapping_type.value, span);
977            }
978            // Check that the array element types are valid.
979            Type::Array(array_type) => {
980                // Check that the array length is valid.
981
982                if let Some(length) = array_type.length.as_u32() {
983                    if length == 0 {
984                        self.emit_err(TypeCheckerError::array_empty(span));
985                    } else if length > self.limits.max_array_elements as u32 {
986                        self.emit_err(TypeCheckerError::array_too_large(length, self.limits.max_array_elements, span));
987                    }
988                } else if let Expression::Literal(_) = &*array_type.length {
989                    // Literal, but not valid u32 (e.g. too big or invalid format)
990                    self.emit_err(TypeCheckerError::array_too_large_for_u32(span));
991                }
992                // else: not a literal, so defer for later
993
994                // Check that the array element type is valid.
995                match array_type.element_type() {
996                    // Array elements cannot be futures.
997                    Type::Future(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_future(span)),
998                    // Array elements cannot be tuples.
999                    Type::Tuple(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span)),
1000                    // Array elements cannot be records.
1001                    Type::Composite(struct_type) => {
1002                        // Look up the type.
1003                        if let Some(struct_) = self.lookup_struct(
1004                            struct_type.program.or(self.scope_state.program_name),
1005                            &struct_type.path.absolute_path(),
1006                        ) {
1007                            // Check that the type is not a record.
1008                            if struct_.is_record {
1009                                self.emit_err(TypeCheckerError::array_element_cannot_be_record(span));
1010                            }
1011                        }
1012                    }
1013                    _ => {} // Do nothing.
1014                }
1015                self.assert_type_is_valid(array_type.element_type(), span);
1016            }
1017            Type::Optional(OptionalType { inner }) => {
1018                match &**inner {
1019                    Type::Composite(struct_type) => {
1020                        // Look up the type.
1021                        if let Some(struct_) = self.lookup_struct(
1022                            struct_type.program.or(self.scope_state.program_name),
1023                            &struct_type.path.absolute_path(),
1024                        ) {
1025                            // Check that the type is not a record.
1026                            if struct_.is_record {
1027                                self.emit_err(TypeCheckerError::optional_wrapping_of_records_unsupported(inner, span));
1028                            }
1029                        }
1030                    }
1031                    Type::Future(_)
1032                    | Type::Identifier(_)
1033                    | Type::Mapping(_)
1034                    | Type::Optional(_)
1035                    | Type::String
1036                    | Type::Signature
1037                    | Type::Tuple(_) => {
1038                        self.emit_err(TypeCheckerError::optional_wrapping_unsupported(inner, span));
1039                    }
1040                    _ => self.assert_type_is_valid(inner, span),
1041                }
1042            }
1043            _ => {} // Do nothing.
1044        }
1045    }
1046
1047    /// Emits an error if the type is not a mapping.
1048    pub fn assert_mapping_type(&self, type_: &Type, span: Span) {
1049        if type_ != &Type::Err && !matches!(type_, Type::Mapping(_)) {
1050            self.emit_err(TypeCheckerError::type_should_be2(type_, "a mapping", span));
1051        }
1052    }
1053
1054    /// Emits an error if the type is not an optional.
1055    pub fn assert_optional_type(&self, type_: &Type, span: Span) {
1056        if type_ != &Type::Err && !matches!(type_, Type::Optional(_)) {
1057            self.emit_err(TypeCheckerError::type_should_be2(type_, "an optional", span));
1058        }
1059    }
1060
1061    pub fn contains_optional_type(&mut self, ty: &Type) -> bool {
1062        let mut visited_paths = IndexSet::<Vec<Symbol>>::new();
1063        self.contains_optional_type_inner(ty, &mut visited_paths)
1064    }
1065
1066    fn contains_optional_type_inner(&mut self, ty: &Type, visited_paths: &mut IndexSet<Vec<Symbol>>) -> bool {
1067        match ty {
1068            Type::Optional(_) => true,
1069
1070            Type::Tuple(tuple) => tuple.elements.iter().any(|e| self.contains_optional_type_inner(e, visited_paths)),
1071
1072            Type::Array(array) => self.contains_optional_type_inner(&array.element_type, visited_paths),
1073
1074            Type::Composite(struct_type) => {
1075                let path = struct_type.path.absolute_path();
1076
1077                // Prevent revisiting the same type
1078                if !visited_paths.insert(path.clone()) {
1079                    return false;
1080                }
1081
1082                if let Some(comp) = self.lookup_struct(struct_type.program.or(self.scope_state.program_name), &path) {
1083                    comp.members
1084                        .iter()
1085                        .any(|Member { type_, .. }| self.contains_optional_type_inner(type_, visited_paths))
1086                } else {
1087                    false
1088                }
1089            }
1090
1091            _ => false,
1092        }
1093    }
1094
1095    pub fn assert_array_type(&self, type_: &Type, span: Span) {
1096        if type_ != &Type::Err && !matches!(type_, Type::Array(_)) {
1097            self.emit_err(TypeCheckerError::type_should_be2(type_, "an array", span));
1098        }
1099    }
1100
1101    /// Helper function to check that the input and output of function are valid
1102    pub fn check_function_signature(&mut self, function: &Function, is_stub: bool) {
1103        let function_path = self
1104            .scope_state
1105            .module_name
1106            .iter()
1107            .cloned()
1108            .chain(std::iter::once(function.identifier.name))
1109            .collect::<Vec<Symbol>>();
1110
1111        self.scope_state.variant = Some(function.variant);
1112
1113        let mut inferred_inputs: Vec<Type> = Vec::new();
1114
1115        if self.scope_state.variant == Some(Variant::AsyncFunction) && !self.scope_state.is_stub {
1116            // Async functions are not allowed to return values.
1117            if !function.output.is_empty() {
1118                self.emit_err(TypeCheckerError::async_function_cannot_return_value(function.span()));
1119            }
1120
1121            // Iterator over the `finalize` member (type Finalizer) of each async transition that calls
1122            // this async function.
1123            let mut caller_finalizers = self
1124                .async_function_callers
1125                .get(&Location::new(self.scope_state.program_name.unwrap(), function_path))
1126                .map(|callers| {
1127                    callers
1128                        .iter()
1129                        .flat_map(|caller| {
1130                            let caller = Location::new(caller.program, caller.path.clone());
1131                            self.state.symbol_table.lookup_function(&caller)
1132                        })
1133                        .flat_map(|fn_symbol| fn_symbol.finalizer.clone())
1134                })
1135                .into_iter()
1136                .flatten();
1137
1138            if let Some(first) = caller_finalizers.next() {
1139                inferred_inputs = first.inferred_inputs.clone();
1140
1141                // If any input is a future that doesn't have the same member type for all
1142                // finalizers, set that member to `Type::Err`.
1143                for finalizer in caller_finalizers {
1144                    assert_eq!(inferred_inputs.len(), finalizer.inferred_inputs.len());
1145                    for (t1, t2) in inferred_inputs.iter_mut().zip(finalizer.inferred_inputs.iter()) {
1146                        Self::merge_types(t1, t2);
1147                    }
1148                }
1149            } else {
1150                self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
1151                    function.identifier.name,
1152                    function.span(),
1153                ));
1154            }
1155        }
1156
1157        // Ensure that, if the function has generic const paramaters, then it must be an `inline`.
1158        // Otherwise, emit an error.
1159        if self.scope_state.variant != Some(Variant::Inline) && !function.const_parameters.is_empty() {
1160            self.emit_err(TypeCheckerError::only_inline_can_have_const_generics(function.identifier.span()));
1161        }
1162
1163        for const_param in &function.const_parameters {
1164            self.visit_type(const_param.type_());
1165
1166            // Restrictions for const parameters
1167            if !matches!(
1168                const_param.type_(),
1169                Type::Boolean | Type::Integer(_) | Type::Address | Type::Scalar | Type::Group | Type::Field
1170            ) {
1171                self.emit_err(TypeCheckerError::bad_const_generic_type(const_param.type_(), const_param.span()));
1172            }
1173
1174            // Add the input to the symbol table.
1175            if let Err(err) = self.state.symbol_table.insert_variable(
1176                self.scope_state.program_name.unwrap(),
1177                &[const_param.identifier().name],
1178                VariableSymbol {
1179                    type_: const_param.type_().clone(),
1180                    span: const_param.identifier.span(),
1181                    declaration: VariableType::ConstParameter,
1182                },
1183            ) {
1184                self.state.handler.emit_err(err);
1185            }
1186
1187            // Add the input to the type table.
1188            self.state.type_table.insert(const_param.identifier().id(), const_param.type_().clone());
1189        }
1190
1191        // The inputs should have access to the const parameters, so handle them after.
1192        for (i, input) in function.input.iter().enumerate() {
1193            self.visit_type(input.type_());
1194
1195            // No need to check compatibility of these types; that's already been done
1196            let table_type = inferred_inputs.get(i).unwrap_or_else(|| input.type_());
1197
1198            // Check that the type of input parameter is defined.
1199            self.assert_type_is_valid(table_type, input.span());
1200
1201            // Check that the type of the input parameter is not a tuple.
1202            if matches!(table_type, Type::Tuple(_)) {
1203                self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input.span()))
1204            }
1205
1206            // Check that the type of the input parameter does not contain an optional.
1207            if self.contains_optional_type(table_type)
1208                && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1209            {
1210                self.emit_err(TypeCheckerError::function_cannot_take_option_as_input(
1211                    input.identifier,
1212                    table_type,
1213                    input.span(),
1214                ))
1215            }
1216
1217            // Make sure only transitions can take a record as an input.
1218            if let Type::Composite(struct_) = table_type {
1219                // Throw error for undefined type.
1220                if !function.variant.is_transition() {
1221                    if let Some(elem) = self
1222                        .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1223                    {
1224                        if elem.is_record {
1225                            self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input.span()))
1226                        }
1227                    } else {
1228                        self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), input.span()));
1229                    }
1230                }
1231            }
1232
1233            // This unwrap works since we assign to `variant` above.
1234            match self.scope_state.variant.unwrap() {
1235                // If the function is a transition function, then check that the parameter mode is not a constant.
1236                Variant::Transition | Variant::AsyncTransition if input.mode() == Mode::Constant => {
1237                    self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input.span()))
1238                }
1239                // If the function is standard function or inline, then check that the parameters do not have an associated mode.
1240                Variant::Function | Variant::Inline if input.mode() != Mode::None => {
1241                    self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input.span()))
1242                }
1243                // If the function is an async function, then check that the input parameter is not constant or private.
1244                Variant::AsyncFunction if matches!(input.mode(), Mode::Constant | Mode::Private) => {
1245                    self.emit_err(TypeCheckerError::async_function_input_must_be_public(input.span()));
1246                }
1247                _ => {} // Do nothing.
1248            }
1249
1250            if matches!(table_type, Type::Future(..)) {
1251                // Future parameters may only appear in async functions.
1252                if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction)) {
1253                    self.emit_err(TypeCheckerError::no_future_parameters(input.span()));
1254                }
1255            }
1256
1257            if !is_stub {
1258                // Add the input to the symbol table.
1259                if let Err(err) = self.state.symbol_table.insert_variable(
1260                    self.scope_state.program_name.unwrap(),
1261                    &[input.identifier().name],
1262                    VariableSymbol {
1263                        type_: table_type.clone(),
1264                        span: input.identifier.span(),
1265                        declaration: VariableType::Input(input.mode()),
1266                    },
1267                ) {
1268                    self.state.handler.emit_err(err);
1269                }
1270
1271                // Add the input to the type table.
1272                self.state.type_table.insert(input.identifier().id(), table_type.clone());
1273            }
1274        }
1275
1276        // Type check the function's return type.
1277        // Note that checking that each of the component types are defined is sufficient to check that `output_type` is defined.
1278        function.output.iter().enumerate().for_each(|(index, function_output)| {
1279            self.visit_type(&function_output.type_);
1280
1281            // If the function is not a transition function, then it cannot output a record.
1282            // Note that an external output must always be a record.
1283            if let Type::Composite(struct_) = function_output.type_.clone() {
1284                if let Some(val) =
1285                    self.lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1286                {
1287                    if val.is_record && !function.variant.is_transition() {
1288                        self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(function_output.span));
1289                    }
1290                }
1291            }
1292
1293            // Check that the output type is valid.
1294            self.assert_type_is_valid(&function_output.type_, function_output.span);
1295
1296            // Check that the type of the output is not a tuple. This is necessary to forbid nested tuples.
1297            if matches!(&function_output.type_, Type::Tuple(_)) {
1298                self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
1299            }
1300
1301            // Check that the type of the input parameter does not contain an optional.
1302            if self.contains_optional_type(&function_output.type_)
1303                && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1304            {
1305                self.emit_err(TypeCheckerError::function_cannot_return_option_as_output(
1306                    &function_output.type_,
1307                    function_output.span(),
1308                ))
1309            }
1310
1311            // Check that the mode of the output is valid.
1312            // For functions, only public and private outputs are allowed
1313            if function_output.mode == Mode::Constant {
1314                self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
1315            }
1316            // Async transitions must return exactly one future, and it must be in the last position.
1317            if self.scope_state.variant == Some(Variant::AsyncTransition)
1318                && ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
1319                    || (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
1320            {
1321                self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
1322            }
1323            // If the function is not an async transition, then it cannot have a future as output.
1324            if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script))
1325                && matches!(function_output.type_, Type::Future(_))
1326            {
1327                self.emit_err(TypeCheckerError::only_async_transition_can_return_future(function_output.span));
1328            }
1329        });
1330
1331        self.visit_type(&function.output_type);
1332    }
1333
1334    /// Merge inferred types into `lhs`.
1335    ///
1336    /// That is, if `lhs` and `rhs` aren't equal, set `lhs` to Type::Err;
1337    /// or, if they're both futures, set any member of `lhs` that isn't
1338    /// equal to the equivalent member of `rhs` to `Type::Err`.
1339    fn merge_types(lhs: &mut Type, rhs: &Type) {
1340        if let Type::Future(f1) = lhs {
1341            if let Type::Future(f2) = rhs {
1342                for (i, type_) in f2.inputs.iter().enumerate() {
1343                    if let Some(lhs_type) = f1.inputs.get_mut(i) {
1344                        Self::merge_types(lhs_type, type_);
1345                    } else {
1346                        f1.inputs.push(Type::Err);
1347                    }
1348                }
1349            } else {
1350                *lhs = Type::Err;
1351            }
1352        } else if !lhs.eq_user(rhs) {
1353            *lhs = Type::Err;
1354        }
1355    }
1356
1357    /// Wrapper around lookup_struct that additionally records all structs that are used in the program.
1358    pub fn lookup_struct(&mut self, program: Option<Symbol>, name: &[Symbol]) -> Option<Composite> {
1359        let record_comp =
1360            program.and_then(|prog| self.state.symbol_table.lookup_record(&Location::new(prog, name.to_vec())));
1361        let comp = record_comp.or_else(|| self.state.symbol_table.lookup_struct(name));
1362        // Record the usage.
1363        if let Some(s) = comp {
1364            // If it's a struct or internal record, mark it used.
1365            if !s.is_record || program == self.scope_state.program_name {
1366                self.used_structs.insert(name.to_vec());
1367            }
1368        }
1369        comp.cloned()
1370    }
1371
1372    /// Inserts variable to symbol table.
1373    pub fn insert_variable(&mut self, inferred_type: Option<Type>, name: &Identifier, type_: Type, span: Span) {
1374        self.insert_symbol_conditional_scope(name.name);
1375
1376        let is_future = match &type_ {
1377            Type::Future(..) => true,
1378            Type::Tuple(tuple_type) if matches!(tuple_type.elements().last(), Some(Type::Future(..))) => true,
1379            _ => false,
1380        };
1381
1382        if is_future {
1383            // It can happen that the call location has not been set if there was an error
1384            // in the call that produced the Future.
1385            if let Some(call_location) = &self.scope_state.call_location {
1386                self.scope_state.futures.insert(name.name, call_location.clone());
1387            }
1388        }
1389
1390        let ty = match (is_future, inferred_type) {
1391            (false, _) => type_,
1392            (true, Some(inferred)) => inferred,
1393            (true, None) => unreachable!("Type checking guarantees the inferred type is present"),
1394        };
1395
1396        // Insert the variable into the symbol table.
1397        if let Err(err) = self.state.symbol_table.insert_variable(
1398            self.scope_state.program_name.unwrap(),
1399            &[name.name],
1400            VariableSymbol { type_: ty.clone(), span, declaration: VariableType::Mut },
1401        ) {
1402            self.state.handler.emit_err(err);
1403        }
1404    }
1405
1406    // Validates whether an access operation is allowed in the current function or block context.
1407    // This prevents illegal use of certain operations depending on whether the code is inside
1408    // an async function, an async block, or a finalize block.
1409    pub fn check_access_allowed(&mut self, name: &str, finalize_op: bool, span: Span) {
1410        // Case 1: Operation is not a finalize op, and we're inside an `async` function.
1411        if self.scope_state.variant == Some(Variant::AsyncFunction) && !finalize_op {
1412            self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_finalize(name, span));
1413        }
1414        // Case 2: Operation is not a finalize op, and we're inside an `async` block.
1415        else if self.async_block_id.is_some() && !finalize_op {
1416            self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_async_block(name, span));
1417        }
1418        // Case 3: Operation *is* a finalize op, but we're *not* inside an async context.
1419        else if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
1420            && self.async_block_id.is_none()
1421            && finalize_op
1422        {
1423            self.state.handler.emit_err(TypeCheckerError::invalid_operation_outside_finalize(name, span));
1424        }
1425    }
1426
1427    pub fn is_external_record(&self, ty: &Type) -> bool {
1428        if let Type::Composite(typ) = &ty {
1429            let this_program = self.scope_state.program_name.unwrap();
1430            let program = typ.program.unwrap_or(this_program);
1431            program != this_program
1432                && self
1433                    .state
1434                    .symbol_table
1435                    .lookup_record(&Location::new(program, typ.path.absolute_path().to_vec()))
1436                    .is_some()
1437        } else {
1438            false
1439        }
1440    }
1441
1442    pub fn parse_integer_literal<I: FromStrRadix>(&self, raw_string: &str, span: Span, type_string: &str) {
1443        let string = raw_string.replace('_', "");
1444        if I::from_str_by_radix(&string).is_err() {
1445            self.state.handler.emit_err(TypeCheckerError::invalid_int_value(string, type_string, span));
1446        }
1447    }
1448
1449    // Emit an error and update `ty` to be `Type::Err` indicating that the type of the expression could not be inferred.
1450    // Also update `type_table` accordingly
1451    pub fn emit_inference_failure_error(&self, ty: &mut Type, expr: &Expression) {
1452        self.emit_err(TypeCheckerError::could_not_determine_type(expr.clone(), expr.span()));
1453        *ty = Type::Err;
1454        self.state.type_table.insert(expr.id(), Type::Err);
1455    }
1456
1457    // Given a `Literal` and its type, if the literal is a numeric `Unsuffixed` literal, ensure it's a valid literal
1458    // given the type. E.g., a `256` is not a valid `u8`.
1459    pub fn check_numeric_literal(&self, input: &Literal, ty: &Type) -> bool {
1460        if let Literal { variant: LiteralVariant::Unsuffixed(s), .. } = input {
1461            let span = input.span();
1462            let has_nondecimal_prefix =
1463                |s: &str| ["0x", "0o", "0b", "-0x", "-0o", "-0b"].iter().any(|p| s.starts_with(p));
1464
1465            macro_rules! parse_int {
1466                ($t:ty, $name:expr) => {
1467                    self.parse_integer_literal::<$t>(s, span, $name)
1468                };
1469            }
1470
1471            match ty {
1472                Type::Integer(kind) => match kind {
1473                    IntegerType::U8 => parse_int!(u8, "u8"),
1474                    IntegerType::U16 => parse_int!(u16, "u16"),
1475                    IntegerType::U32 => parse_int!(u32, "u32"),
1476                    IntegerType::U64 => parse_int!(u64, "u64"),
1477                    IntegerType::U128 => parse_int!(u128, "u128"),
1478                    IntegerType::I8 => parse_int!(i8, "i8"),
1479                    IntegerType::I16 => parse_int!(i16, "i16"),
1480                    IntegerType::I32 => parse_int!(i32, "i32"),
1481                    IntegerType::I64 => parse_int!(i64, "i64"),
1482                    IntegerType::I128 => parse_int!(i128, "i128"),
1483                },
1484                Type::Group => {
1485                    if has_nondecimal_prefix(s) {
1486                        // This is not checked in the parser for unsuffixed numerals. So do that here.
1487                        self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1488                        return false;
1489                    } else {
1490                        let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1491                        if !trimmed.is_empty()
1492                            && format!("{trimmed}group")
1493                                .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1494                                .is_err()
1495                        {
1496                            self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1497                            return false;
1498                        }
1499                    }
1500                }
1501                Type::Field | Type::Scalar => {
1502                    if has_nondecimal_prefix(s) {
1503                        // This is not checked in the parser for unsuffixed numerals. So do that here.
1504                        self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1505                        return false;
1506                    }
1507                }
1508                _ => {
1509                    // Other types aren't expected here
1510                }
1511            }
1512        }
1513        true
1514    }
1515}