1use 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 anyhow::bail;
26use indexmap::{IndexMap, IndexSet};
27use snarkvm::{
28 console::algorithms::ECDSASignature,
29 prelude::PrivateKey,
30 synthesizer::program::{CommitVariant, DeserializeVariant, ECDSAVerifyVariant, HashVariant, SerializeVariant},
31};
32use std::{ops::Deref, str::FromStr};
33
34pub struct TypeCheckingVisitor<'a> {
35 pub state: &'a mut CompilerState,
36 pub scope_state: ScopeState,
38 pub async_function_input_types: IndexMap<Location, Vec<Type>>,
40 pub async_function_callers: IndexMap<Location, IndexSet<Location>>,
42 pub used_structs: IndexSet<Vec<Symbol>>,
44 pub limits: TypeCheckingInput,
46 pub conditional_scopes: Vec<IndexSet<Symbol>>,
48 pub async_block_id: Option<NodeID>,
50}
51
52impl TypeCheckingVisitor<'_> {
53 pub fn in_scope<T>(&mut self, id: NodeID, func: impl FnOnce(&mut Self) -> T) -> T {
54 self.state.symbol_table.enter_scope(Some(id));
55 let result = func(self);
56 self.state.symbol_table.enter_parent();
57 result
58 }
59
60 pub fn in_conditional_scope<T>(&mut self, func: impl FnOnce(&mut Self) -> T) -> T {
61 self.conditional_scopes.push(Default::default());
62 let result = func(self);
63 self.conditional_scopes.pop();
64 result
65 }
66
67 pub fn insert_symbol_conditional_scope(&mut self, symbol: Symbol) {
68 self.conditional_scopes.last_mut().expect("A conditional scope must be present.").insert(symbol);
69 }
70
71 pub fn symbol_in_conditional_scope(&mut self, symbol: Symbol) -> bool {
72 self.conditional_scopes.last().map(|set| set.contains(&symbol)).unwrap_or(false)
73 }
74
75 pub fn emit_err(&self, err: TypeCheckerError) {
77 self.state.handler.emit_err(err);
78 }
79
80 pub fn emit_warning(&mut self, warning: TypeCheckerWarning) {
82 if self.state.warnings.insert(warning.clone().into()) {
83 self.state.handler.emit_warning(warning);
84 }
85 }
86
87 pub fn check_eq_types(&self, t1: &Option<Type>, t2: &Option<Type>, span: Span) {
89 match (t1, t2) {
90 (Some(t1), Some(t2)) if !t1.eq_flat_relaxed(t2) => {
91 self.emit_err(TypeCheckerError::type_should_be(t1, t2, span))
92 }
93 (Some(type_), None) | (None, Some(type_)) => {
94 self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
95 }
96 _ => {}
97 }
98 }
99
100 pub fn assert_and_return_type(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
103 if expected.is_some() && !matches!(expected, Some(Type::Err)) {
105 self.check_eq_types(&Some(actual.clone()), expected, span);
106 }
107 actual
108 }
109
110 pub fn maybe_assert_type(&mut self, actual: &Type, expected: &Option<Type>, span: Span) {
111 if let Some(expected) = expected {
112 self.assert_type(actual, expected, span);
113 }
114 }
115
116 pub fn assert_type(&mut self, actual: &Type, expected: &Type, span: Span) {
117 if actual != &Type::Err && !actual.can_coerce_to(expected) {
118 self.emit_err(TypeCheckerError::type_should_be2(actual, format!("type `{expected}`"), span));
120 }
121 }
122
123 pub fn unwrap_optional_type(&self, expected: &Option<Type>) -> Option<Type> {
126 match expected {
127 Some(Type::Optional(opt_type)) => Some(*opt_type.inner.clone()),
128 other => other.clone(),
129 }
130 }
131
132 pub fn wrap_if_optional(&self, actual: Type, destination: &Option<Type>) -> Type {
135 match (actual, destination) {
136 (actual_type, Some(Type::Optional(opt_type))) if !matches!(actual_type, Type::Optional(_)) => {
138 if actual_type.can_coerce_to(&opt_type.inner) {
140 Type::Optional(OptionalType { inner: Box::new(actual_type) })
141 } else {
142 actual_type
143 }
144 }
145 (actual_type, _) => actual_type,
146 }
147 }
148
149 pub fn assert_int_type(&self, type_: &Type, span: Span) {
150 if !matches!(type_, Type::Err | Type::Integer(_)) {
151 self.emit_err(TypeCheckerError::type_should_be2(type_, "an integer", span));
152 }
153 }
154
155 pub fn assert_unsigned_type(&self, type_: &Type, span: Span) {
156 if !matches!(
157 type_,
158 Type::Err
159 | Type::Integer(IntegerType::U8)
160 | Type::Integer(IntegerType::U16)
161 | Type::Integer(IntegerType::U32)
162 | Type::Integer(IntegerType::U64)
163 | Type::Integer(IntegerType::U128)
164 ) {
165 self.emit_err(TypeCheckerError::type_should_be2(type_, "an unsigned integer", span));
166 }
167 }
168
169 pub fn assert_bool_int_type(&self, type_: &Type, span: Span) {
170 if !matches!(
171 type_,
172 Type::Err
173 | Type::Boolean
174 | Type::Integer(IntegerType::U8)
175 | Type::Integer(IntegerType::U16)
176 | Type::Integer(IntegerType::U32)
177 | Type::Integer(IntegerType::U64)
178 | Type::Integer(IntegerType::U128)
179 | Type::Integer(IntegerType::I8)
180 | Type::Integer(IntegerType::I16)
181 | Type::Integer(IntegerType::I32)
182 | Type::Integer(IntegerType::I64)
183 | Type::Integer(IntegerType::I128)
184 ) {
185 self.emit_err(TypeCheckerError::type_should_be2(type_, "a bool or integer", span));
186 }
187 }
188
189 pub fn assert_field_int_type(&self, type_: &Type, span: Span) {
190 if !matches!(
191 type_,
192 Type::Err
193 | Type::Field
194 | Type::Integer(IntegerType::U8)
195 | Type::Integer(IntegerType::U16)
196 | Type::Integer(IntegerType::U32)
197 | Type::Integer(IntegerType::U64)
198 | Type::Integer(IntegerType::U128)
199 | Type::Integer(IntegerType::I8)
200 | Type::Integer(IntegerType::I16)
201 | Type::Integer(IntegerType::I32)
202 | Type::Integer(IntegerType::I64)
203 | Type::Integer(IntegerType::I128)
204 ) {
205 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field or integer", span));
206 }
207 }
208
209 pub fn assert_field_group_int_type(&self, type_: &Type, span: Span) {
210 if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Integer(_)) {
211 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, group, or integer", span));
212 }
213 }
214
215 pub fn get_core_constant(&self, type_: &Type, constant: &Identifier) -> Option<CoreConstant> {
217 if let Type::Identifier(ident) = type_ {
218 match CoreConstant::from_symbols(ident.name, constant.name) {
220 None => {
221 self.emit_err(TypeCheckerError::invalid_core_constant(ident.name, constant.name, ident.span()));
223 }
224 Some(core_constant) => return Some(core_constant),
225 }
226 }
227 None
228 }
229
230 pub fn get_core_function_call(&self, associated_function: &AssociatedFunctionExpression) -> Option<CoreFunction> {
233 match CoreFunction::try_from(associated_function).ok() {
235 None => {
236 self.emit_err(TypeCheckerError::invalid_core_function(
238 associated_function.variant.name,
239 associated_function.name.name,
240 associated_function.variant.span(),
241 ));
242 None
243 }
244 core_function @ Some(CoreFunction::Deserialize(_, _)) => core_function,
245 Some(core_instruction) => {
246 if !associated_function.type_parameters.is_empty() {
248 self.emit_err(TypeCheckerError::custom(
249 format!(
250 "The core function `{}::{}` cannot have type parameters.",
251 associated_function.variant, associated_function.name
252 ),
253 associated_function.name.span(),
254 ));
255 return None;
256 };
257
258 Some(core_instruction)
259 }
260 }
261 }
262
263 pub fn check_core_function_call(
267 &mut self,
268 core_function: CoreFunction,
269 arguments: &[Expression],
270 expected: &Option<Type>,
271 function_span: Span,
272 ) -> Type {
273 if arguments.len() != core_function.num_args() {
275 self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
276 core_function.num_args(),
277 arguments.len(),
278 function_span,
279 ));
280 return Type::Err;
281 }
282
283 let arguments = match core_function {
294 CoreFunction::OptionalUnwrap => {
295 let [opt] = arguments else { panic!("number of arguments is already checked") };
297
298 let opt_ty = if let Some(expected) = expected {
300 self.visit_expression(
301 opt,
302 &Some(Type::Optional(OptionalType { inner: Box::new(expected.clone()) })),
303 )
304 } else {
305 self.visit_expression(opt, &None)
306 };
307
308 vec![(opt_ty, opt)]
309 }
310
311 CoreFunction::OptionalUnwrapOr => {
312 let [opt, fallback] = arguments else { panic!("number of arguments is already checked") };
314
315 if let Some(expected) = expected {
316 let opt_ty = self.visit_expression(
318 opt,
319 &Some(Type::Optional(OptionalType { inner: Box::new(expected.clone()) })),
320 );
321 let fallback_ty = self.visit_expression(fallback, &Some(expected.clone()));
322 vec![(opt_ty, opt), (fallback_ty, fallback)]
323 } else {
324 let opt_ty = self.visit_expression(opt, &None);
326 let fallback_ty = if let Type::Optional(OptionalType { inner }) = &opt_ty {
327 self.visit_expression(fallback, &Some(*inner.clone()))
328 } else {
329 self.visit_expression(fallback, &None)
330 };
331 vec![(opt_ty, opt), (fallback_ty, fallback)]
332 }
333 }
334
335 CoreFunction::Get => {
337 let [container, key_or_index] = arguments else { panic!("number of arguments is already checked") };
338
339 let container_ty = self.visit_expression(container, &None);
340
341 let key_or_index_ty = match container_ty {
343 Type::Vector(_) => self.visit_expression_infer_default_u32(key_or_index),
344 Type::Mapping(MappingType { ref key, .. }) => {
345 self.visit_expression(key_or_index, &Some(*key.clone()))
346 }
347 _ => self.visit_expression(key_or_index, &None),
348 };
349
350 vec![(container_ty, container), (key_or_index_ty, key_or_index)]
351 }
352
353 CoreFunction::Set => {
355 let [container, key_or_index, val] = arguments else {
356 panic!("number of arguments is already checked")
357 };
358
359 let container_ty = self.visit_expression(container, &None);
360
361 let key_or_index_ty = match container_ty {
362 Type::Vector(_) => self.visit_expression_infer_default_u32(key_or_index),
363 Type::Mapping(MappingType { ref key, .. }) => {
364 self.visit_expression(key_or_index, &Some(*key.clone()))
365 }
366 _ => self.visit_expression(key_or_index, &None),
367 };
368
369 let val_ty = match container_ty {
370 Type::Vector(VectorType { ref element_type }) => {
371 self.visit_expression(val, &Some(*element_type.clone()))
372 }
373 Type::Mapping(MappingType { ref value, .. }) => self.visit_expression(val, &Some(*value.clone())),
374 _ => self.visit_expression(val, &None),
375 };
376
377 vec![(container_ty, container), (key_or_index_ty, key_or_index), (val_ty, val)]
378 }
379
380 CoreFunction::VectorPush => {
381 let [vec, val] = arguments else { panic!("number of arguments is already checked") };
382
383 let vec_ty = self.visit_expression(vec, &None);
385
386 let val_ty = if let Type::Vector(VectorType { element_type }) = &vec_ty {
388 self.visit_expression(val, &Some(*element_type.clone()))
389 } else {
390 self.visit_expression(val, &None)
391 };
392
393 vec![(vec_ty, vec), (val_ty, val)]
394 }
395
396 CoreFunction::VectorSwapRemove => {
397 let [vec, index] = arguments else { panic!("number of arguments is already checked") };
398
399 let vec_ty = self.visit_expression(vec, &None);
400
401 let index_ty = self.visit_expression_infer_default_u32(index);
403
404 vec![(vec_ty, vec), (index_ty, index)]
405 }
406
407 _ => {
409 arguments.iter().map(|arg| (self.visit_expression_reject_numeric(arg, &None), arg)).collect::<Vec<_>>()
410 }
411 };
412
413 let assert_not_mapping_tuple_unit = |type_: &Type, span: Span| {
414 if matches!(type_, Type::Mapping(_) | Type::Tuple(_) | Type::Unit) {
415 self.emit_err(TypeCheckerError::type_should_be2(type_, "anything but a mapping, tuple, or unit", span));
416 }
417 };
418
419 let assert_pedersen_64_bit_input = |type_: &Type, span: Span| {
423 if !matches!(
424 type_,
425 Type::Integer(IntegerType::U8)
426 | Type::Integer(IntegerType::U16)
427 | Type::Integer(IntegerType::U32)
428 | Type::Integer(IntegerType::I8)
429 | Type::Integer(IntegerType::I16)
430 | Type::Integer(IntegerType::I32)
431 | Type::Boolean
432 | Type::Err
433 ) {
434 self.emit_err(TypeCheckerError::type_should_be2(
435 type_,
436 "an integer of less than 64 bits or a bool",
437 span,
438 ));
439 }
440 };
441
442 let assert_pedersen_128_bit_input = |type_: &Type, span: Span| {
449 if !matches!(
450 type_,
451 Type::Integer(IntegerType::U8)
452 | Type::Integer(IntegerType::U16)
453 | Type::Integer(IntegerType::U32)
454 | Type::Integer(IntegerType::U64)
455 | Type::Integer(IntegerType::I8)
456 | Type::Integer(IntegerType::I16)
457 | Type::Integer(IntegerType::I32)
458 | Type::Integer(IntegerType::I64)
459 | Type::Boolean
460 | Type::Err
461 ) {
462 self.emit_err(TypeCheckerError::type_should_be2(
463 type_,
464 "an integer of less than 128 bits or a bool",
465 span,
466 ));
467 }
468 };
469
470 let program_id_regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z0-9_]*\.aleo$").unwrap();
472
473 match core_function {
475 CoreFunction::Commit(variant, type_) => {
476 match variant {
477 CommitVariant::CommitPED64 => {
478 assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
479 }
480 CommitVariant::CommitPED128 => {
481 assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
482 }
483 _ => {
484 assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
485 }
486 }
487 self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
488 type_.into()
489 }
490 CoreFunction::Hash(variant, type_) => {
491 if variant.requires_byte_alignment() {
493 let input_type = &arguments[0].0;
495 let size_in_bits = match self.state.network {
497 NetworkName::TestnetV0 => input_type
498 .size_in_bits::<TestnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
499 NetworkName::MainnetV0 => input_type
500 .size_in_bits::<MainnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
501 NetworkName::CanaryV0 => input_type
502 .size_in_bits::<CanaryV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
503 };
504 if let Ok(size_in_bits) = size_in_bits {
505 if size_in_bits % 8 != 0 {
507 self.emit_err(TypeCheckerError::type_should_be2(
508 input_type,
509 "a type with a size in bits that is a multiple of 8",
510 arguments[0].1.span(),
511 ));
512 return Type::Err;
513 }
514 };
515 }
516 match variant {
517 HashVariant::HashPED64 => {
518 assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
519 }
520 HashVariant::HashPED128 => {
521 assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
522 }
523 _ => {
524 assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
525 }
526 }
527 type_
528 }
529 CoreFunction::ECDSAVerify(variant) => {
530 let signature_size = ECDSASignature::SIGNATURE_SIZE_IN_BYTES;
532 let Type::Array(array_type) = &arguments[0].0 else {
534 self.emit_err(TypeCheckerError::type_should_be2(
535 &arguments[0].0,
536 format!("a [u8; {signature_size}]"),
537 arguments[0].1.span(),
538 ));
539 return Type::Err;
540 };
541 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[0].1.span());
542 if let Some(length) = array_type.length.as_u32()
543 && length as usize != signature_size
544 {
545 self.emit_err(TypeCheckerError::type_should_be2(
546 &arguments[0].0,
547 format!("a [u8; {signature_size}]"),
548 arguments[0].1.span(),
549 ));
550 return Type::Err;
551 };
552
553 let is_eth = match variant {
555 ECDSAVerifyVariant::Digest => false,
556 ECDSAVerifyVariant::DigestEth => true,
557 ECDSAVerifyVariant::HashKeccak256 => false,
558 ECDSAVerifyVariant::HashKeccak256Raw => false,
559 ECDSAVerifyVariant::HashKeccak256Eth => true,
560 ECDSAVerifyVariant::HashKeccak384 => false,
561 ECDSAVerifyVariant::HashKeccak384Raw => false,
562 ECDSAVerifyVariant::HashKeccak384Eth => true,
563 ECDSAVerifyVariant::HashKeccak512 => false,
564 ECDSAVerifyVariant::HashKeccak512Raw => false,
565 ECDSAVerifyVariant::HashKeccak512Eth => true,
566 ECDSAVerifyVariant::HashSha3_256 => false,
567 ECDSAVerifyVariant::HashSha3_256Raw => false,
568 ECDSAVerifyVariant::HashSha3_256Eth => true,
569 ECDSAVerifyVariant::HashSha3_384 => false,
570 ECDSAVerifyVariant::HashSha3_384Raw => false,
571 ECDSAVerifyVariant::HashSha3_384Eth => true,
572 ECDSAVerifyVariant::HashSha3_512 => false,
573 ECDSAVerifyVariant::HashSha3_512Raw => false,
574 ECDSAVerifyVariant::HashSha3_512Eth => true,
575 };
576 let expected_length = if is_eth {
578 ECDSASignature::ETHEREUM_ADDRESS_SIZE_IN_BYTES
579 } else {
580 ECDSASignature::VERIFYING_KEY_SIZE_IN_BYTES
581 };
582 let Type::Array(array_type) = &arguments[1].0 else {
584 self.emit_err(TypeCheckerError::type_should_be2(
585 &arguments[1].0,
586 format!("a [u8; {expected_length}]"),
587 arguments[1].1.span(),
588 ));
589 return Type::Err;
590 };
591 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[1].1.span());
592 if let Some(length) = array_type.length.as_u32()
593 && length as usize != expected_length
594 {
595 self.emit_err(TypeCheckerError::type_should_be2(
596 &arguments[1].0,
597 format!("a [u8; {expected_length}]"),
598 arguments[1].1.span(),
599 ));
600 return Type::Err;
601 };
602
603 if matches!(&arguments[2].0, Type::Mapping(_) | Type::Tuple(_) | Type::Unit) {
605 self.emit_err(TypeCheckerError::type_should_be2(
606 &arguments[2].0,
607 "anything but a mapping, tuple, or unit",
608 arguments[2].1.span(),
609 ));
610 }
611
612 if matches!(variant, ECDSAVerifyVariant::Digest | ECDSAVerifyVariant::DigestEth) {
614 let expected_length = ECDSASignature::PREHASH_SIZE_IN_BYTES;
616 let Type::Array(array_type) = &arguments[2].0 else {
618 self.emit_err(TypeCheckerError::type_should_be2(
619 &arguments[2].0,
620 format!("a [u8; {expected_length}]"),
621 arguments[2].1.span(),
622 ));
623 return Type::Err;
624 };
625 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[2].1.span());
626 if let Some(length) = array_type.length.as_u32()
627 && length as usize != expected_length
628 {
629 self.emit_err(TypeCheckerError::type_should_be2(
630 &arguments[2].0,
631 format!("a [u8; {expected_length}]"),
632 arguments[2].1.span(),
633 ));
634 return Type::Err;
635 }
636 }
637
638 if variant.requires_byte_alignment() {
640 let input_type = &arguments[2].0;
642 let size_in_bits = match self.state.network {
644 NetworkName::TestnetV0 => input_type
645 .size_in_bits::<TestnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
646 NetworkName::MainnetV0 => input_type
647 .size_in_bits::<MainnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
648 NetworkName::CanaryV0 => input_type
649 .size_in_bits::<CanaryV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
650 };
651 if let Ok(size_in_bits) = size_in_bits {
652 if size_in_bits % 8 != 0 {
654 self.emit_err(TypeCheckerError::type_should_be2(
655 input_type,
656 "a type with a size in bits that is a multiple of 8",
657 arguments[2].1.span(),
658 ));
659 return Type::Err;
660 }
661 };
662 }
663
664 Type::Boolean
665 }
666 CoreFunction::Get => {
667 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
668 self.check_access_allowed("Vector::get", true, function_span);
670
671 Type::Optional(OptionalType { inner: Box::new(*element_type.clone()) })
672 } else if let Type::Mapping(MappingType { value, .. }) = &arguments[0].0 {
673 self.check_access_allowed("Mapping::get", true, function_span);
675
676 *value.clone()
677 } else {
678 self.assert_vector_or_mapping_type(&arguments[0].0, arguments[0].1.span());
679 Type::Err
680 }
681 }
682 CoreFunction::Set => {
683 if arguments[0].0.is_vector() {
684 self.check_access_allowed("Vector::set", true, function_span);
686
687 Type::Unit
688 } else if let Type::Mapping(_) = &arguments[0].0 {
689 self.check_access_allowed("Mapping::set", true, function_span);
691
692 Type::Unit
693 } else {
694 self.assert_vector_or_mapping_type(&arguments[0].0, arguments[0].1.span());
695 Type::Err
696 }
697 }
698 CoreFunction::MappingGetOrUse => {
699 self.check_access_allowed("Mapping::get_or_use", true, function_span);
701 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
703
704 let Type::Mapping(mapping_type) = &arguments[0].0 else {
705 return Type::Err;
707 };
708
709 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
711 self.assert_type(&arguments[2].0, &mapping_type.value, arguments[2].1.span());
713
714 mapping_type.value.deref().clone()
715 }
716 CoreFunction::MappingRemove => {
717 self.check_access_allowed("Mapping::remove", true, function_span);
719 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
721
722 let Type::Mapping(mapping_type) = &arguments[0].0 else {
723 return Type::Err;
725 };
726
727 if mapping_type.program != self.scope_state.program_name.unwrap() {
729 self.state
730 .handler
731 .emit_err(TypeCheckerError::cannot_modify_external_mapping("remove", function_span));
732 }
733
734 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
736
737 Type::Unit
738 }
739 CoreFunction::MappingContains => {
740 self.check_access_allowed("Mapping::contains", true, function_span);
742 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
744
745 let Type::Mapping(mapping_type) = &arguments[0].0 else {
746 return Type::Err;
748 };
749
750 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
752
753 Type::Boolean
754 }
755 CoreFunction::OptionalUnwrap => {
756 self.assert_optional_type(&arguments[0].0, arguments[0].1.span());
758
759 match &arguments[0].0 {
760 Type::Optional(opt) => opt.inner.deref().clone(),
761 _ => Type::Err,
762 }
763 }
764 CoreFunction::OptionalUnwrapOr => {
765 self.assert_optional_type(&arguments[0].0, arguments[0].1.span());
767
768 match &arguments[0].0 {
769 Type::Optional(OptionalType { inner }) => {
770 self.assert_type(&arguments[1].0, inner, arguments[1].1.span());
772 inner.deref().clone()
773 }
774 _ => Type::Err,
775 }
776 }
777 CoreFunction::VectorPush => {
778 self.check_access_allowed("Vector::push", true, function_span);
779
780 match &arguments[0].0 {
782 Type::Vector(VectorType { element_type }) => {
783 self.assert_type(&arguments[1].0, element_type, arguments[1].1.span());
785 Type::Unit
786 }
787 _ => {
788 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
789 Type::Err
790 }
791 }
792 }
793 CoreFunction::VectorLen => {
794 self.check_access_allowed("Vector::len", true, function_span);
795
796 if arguments[0].0.is_vector() {
797 Type::Integer(IntegerType::U32)
798 } else {
799 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
800 Type::Err
801 }
802 }
803 CoreFunction::VectorPop => {
804 self.check_access_allowed("Vector::pop", true, function_span);
805
806 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
807 Type::Optional(OptionalType { inner: Box::new(*element_type.clone()) })
808 } else {
809 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
810 Type::Err
811 }
812 }
813 CoreFunction::VectorSwapRemove => {
814 self.check_access_allowed("Vector::swap_remove", true, function_span);
815
816 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
817 *element_type.clone()
818 } else {
819 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
820 Type::Err
821 }
822 }
823 CoreFunction::VectorClear => {
824 if arguments[0].0.is_vector() {
825 Type::Unit
826 } else {
827 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
828 Type::Err
829 }
830 }
831 CoreFunction::GroupToXCoordinate | CoreFunction::GroupToYCoordinate => {
832 self.assert_type(&arguments[0].0, &Type::Group, arguments[0].1.span());
834 Type::Field
835 }
836 CoreFunction::ChaChaRand(type_) => type_.into(),
837 CoreFunction::SignatureVerify => {
838 assert_not_mapping_tuple_unit(&arguments[2].0, arguments[2].1.span());
841
842 self.assert_type(&arguments[0].0, &Type::Signature, arguments[0].1.span());
844 self.assert_type(&arguments[1].0, &Type::Address, arguments[1].1.span());
846 Type::Boolean
847 }
848 CoreFunction::FutureAwait => Type::Unit,
849 CoreFunction::ProgramChecksum => {
850 let (type_, expression) = &arguments[0];
852 let span = expression.span();
853 match expression {
855 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
856 if program_id_regex.is_match(s) => {}
857 _ => {
858 self.emit_err(TypeCheckerError::custom(
859 "`Program::checksum` must be called on a program ID, e.g. `foo.aleo`",
860 span,
861 ));
862 }
863 }
864 self.assert_type(type_, &Type::Address, span);
866 Type::Array(ArrayType::new(
868 Type::Integer(IntegerType::U8),
869 Expression::Literal(Literal::integer(
870 IntegerType::U8,
871 "32".to_string(),
872 Default::default(),
873 Default::default(),
874 )),
875 ))
876 }
877 CoreFunction::ProgramEdition => {
878 let (type_, expression) = &arguments[0];
880 let span = expression.span();
881 match expression {
883 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
884 if program_id_regex.is_match(s) => {}
885 _ => {
886 self.emit_err(TypeCheckerError::custom(
887 "`Program::edition` must be called on a program ID, e.g. `foo.aleo`",
888 span,
889 ));
890 }
891 }
892 self.assert_type(type_, &Type::Address, span);
894 Type::Integer(IntegerType::U16)
896 }
897 CoreFunction::ProgramOwner => {
898 let (type_, expression) = &arguments[0];
900 let span = expression.span();
901 match expression {
903 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
904 if program_id_regex.is_match(s) => {}
905 _ => {
906 self.emit_err(TypeCheckerError::custom(
907 "`Program::program_owner` must be called on a program ID, e.g. `foo.aleo`",
908 span,
909 ));
910 }
911 }
912 self.assert_type(type_, &Type::Address, span);
914 Type::Address
916 }
917 CoreFunction::Serialize(variant) => {
918 let is_raw = match variant {
920 SerializeVariant::ToBits => false,
921 SerializeVariant::ToBitsRaw => true,
922 };
923 let input_type = &arguments[0].0;
925
926 let is_allowed_literal_type = |type_: &Type| -> bool {
928 matches!(
929 type_,
930 Type::Boolean
931 | Type::Field
932 | Type::Group
933 | Type::Scalar
934 | Type::Signature
935 | Type::Address
936 | Type::Integer(_)
937 | Type::String
938 | Type::Numeric
939 )
940 };
941
942 let is_allowed = match input_type {
944 Type::Array(array_type) => is_allowed_literal_type(array_type.base_element_type()),
945 type_ => is_allowed_literal_type(type_),
946 };
947 if !is_allowed {
948 self.emit_err(TypeCheckerError::type_should_be2(
949 input_type,
950 "a literal type or an (multi-dimensional) array of literal types",
951 arguments[0].1.span(),
952 ));
953 return Type::Err;
954 }
955
956 let size_in_bits = match self.state.network {
958 NetworkName::TestnetV0 => {
959 input_type.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
960 }
961 NetworkName::MainnetV0 => {
962 input_type.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
963 }
964 NetworkName::CanaryV0 => {
965 input_type.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
966 }
967 };
968
969 if let Ok(size_in_bits) = size_in_bits {
970 let size_in_bits = if size_in_bits > self.limits.max_array_elements {
972 self.emit_err(TypeCheckerError::custom(
973 format!("The input type to `Serialize::*` is too large. Found {size_in_bits} bits, but the maximum allowed is {} bits.", self.limits.max_array_elements),
974 arguments[0].1.span(),
975 ));
976 return Type::Err;
977 } else if size_in_bits == 0 {
978 self.emit_err(TypeCheckerError::custom(
979 "The input type to `Serialize::*` is empty.",
980 arguments[0].1.span(),
981 ));
982 return Type::Err;
983 } else {
984 u32::try_from(size_in_bits).expect("`max_array_elements` should fit in a u32")
985 };
986
987 return Type::Array(ArrayType::bit_array(size_in_bits));
989 }
990
991 Type::Err
993 }
994 CoreFunction::Deserialize(variant, type_) => {
995 let is_raw = match variant {
997 DeserializeVariant::FromBits => false,
998 DeserializeVariant::FromBitsRaw => true,
999 };
1000 let input_type = &arguments[0].0;
1002
1003 let size_in_bits = match self.state.network {
1005 NetworkName::TestnetV0 => {
1006 type_.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
1007 }
1008 NetworkName::MainnetV0 => {
1009 type_.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
1010 }
1011 NetworkName::CanaryV0 => {
1012 type_.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
1013 }
1014 };
1015
1016 if let Ok(size_in_bits) = size_in_bits {
1017 let size_in_bits = if size_in_bits > self.limits.max_array_elements {
1019 self.emit_err(TypeCheckerError::custom(
1020 format!("The output type of `Deserialize::*` is too large. Found {size_in_bits} bits, but the maximum allowed is {} bits.", self.limits.max_array_elements),
1021 arguments[0].1.span(),
1022 ));
1023 return Type::Err;
1024 } else if size_in_bits == 0 {
1025 self.emit_err(TypeCheckerError::custom(
1026 "The output type of `Deserialize::*` is empty.",
1027 arguments[0].1.span(),
1028 ));
1029 return Type::Err;
1030 } else {
1031 u32::try_from(size_in_bits).expect("`max_array_elements` should fit in a u32")
1032 };
1033
1034 let expected_type = Type::Array(ArrayType::bit_array(size_in_bits));
1036 if !input_type.eq_flat_relaxed(&expected_type) {
1037 self.emit_err(TypeCheckerError::type_should_be2(
1038 input_type,
1039 format!("an array of {size_in_bits} bits"),
1040 arguments[0].1.span(),
1041 ));
1042 return Type::Err;
1043 }
1044 };
1045
1046 type_.clone()
1047 }
1048 CoreFunction::CheatCodePrintMapping => {
1049 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
1050 Type::Unit
1051 }
1052 CoreFunction::CheatCodeSetBlockHeight => {
1053 self.assert_type(&arguments[0].0, &Type::Integer(IntegerType::U32), arguments[0].1.span());
1054 Type::Unit
1055 }
1056 CoreFunction::CheatCodeSetSigner => {
1057 self.assert_type(&arguments[0].0, &Type::String, arguments[0].1.span());
1059 if let Expression::Literal(Literal { variant: LiteralVariant::String(s), .. }) = arguments[0].1 {
1061 let s = s.replace("\"", "");
1062 let is_err = match self.state.network {
1063 NetworkName::TestnetV0 => PrivateKey::<TestnetV0>::from_str(&s).is_err(),
1064 NetworkName::MainnetV0 => PrivateKey::<MainnetV0>::from_str(&s).is_err(),
1065 NetworkName::CanaryV0 => PrivateKey::<CanaryV0>::from_str(&s).is_err(),
1066 };
1067 if is_err {
1068 self.emit_err(TypeCheckerError::custom(
1069 "`CheatCode::set_signer` must be called with a valid private key",
1070 arguments[0].1.span(),
1071 ));
1072 }
1073 };
1074 Type::Unit
1075 }
1076 }
1077 }
1078
1079 pub fn assert_member_is_not_record(&mut self, span: Span, parent: Symbol, type_: &Type) {
1081 match type_ {
1082 Type::Composite(struct_)
1083 if self
1084 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1085 .is_some_and(|struct_| struct_.is_record) =>
1086 {
1087 self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(
1088 parent,
1089 struct_.path.clone(),
1090 span,
1091 ))
1092 }
1093 Type::Tuple(tuple_type) => {
1094 for type_ in tuple_type.elements().iter() {
1095 self.assert_member_is_not_record(span, parent, type_)
1096 }
1097 }
1098 _ => {} }
1100 }
1101
1102 pub fn assert_type_is_valid(&mut self, type_: &Type, span: Span) {
1104 match type_ {
1105 Type::Unit => {
1107 self.emit_err(TypeCheckerError::unit_type_only_return(span));
1108 }
1109 Type::String => {
1111 self.emit_err(TypeCheckerError::strings_are_not_supported(span));
1112 }
1113 Type::Composite(struct_)
1115 if self
1116 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1117 .is_none() =>
1118 {
1119 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), span));
1120 }
1121 Type::Tuple(tuple_type) => {
1123 for type_ in tuple_type.elements().iter() {
1124 self.assert_type_is_valid(type_, span);
1125 }
1126 }
1127 Type::Mapping(mapping_type) => {
1129 self.assert_type_is_valid(&mapping_type.key, span);
1130 self.assert_type_is_valid(&mapping_type.value, span);
1131 }
1132 Type::Array(array_type) => {
1134 if let Some(length) = array_type.length.as_u32() {
1137 if length == 0 {
1138 self.emit_err(TypeCheckerError::array_empty(span));
1139 } else if length > self.limits.max_array_elements as u32 {
1140 self.emit_err(TypeCheckerError::array_too_large(length, self.limits.max_array_elements, span));
1141 }
1142 } else if let Expression::Literal(_) = &*array_type.length {
1143 self.emit_err(TypeCheckerError::array_too_large_for_u32(span));
1145 }
1146 match array_type.element_type() {
1150 Type::Future(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_future(span)),
1152 Type::Tuple(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span)),
1154 Type::Composite(struct_type) => {
1156 if let Some(struct_) = self.lookup_struct(
1158 struct_type.program.or(self.scope_state.program_name),
1159 &struct_type.path.absolute_path(),
1160 ) {
1161 if struct_.is_record {
1163 self.emit_err(TypeCheckerError::array_element_cannot_be_record(span));
1164 }
1165 }
1166 }
1167 _ => {} }
1169 self.assert_type_is_valid(array_type.element_type(), span);
1170 }
1171 Type::Optional(OptionalType { inner }) => {
1172 match &**inner {
1173 Type::Composite(struct_type) => {
1174 if let Some(struct_) = self.lookup_struct(
1176 struct_type.program.or(self.scope_state.program_name),
1177 &struct_type.path.absolute_path(),
1178 ) {
1179 if struct_.is_record {
1181 self.emit_err(TypeCheckerError::optional_wrapping_of_records_unsupported(inner, span));
1182 }
1183 }
1184 }
1185 Type::Future(_)
1186 | Type::Identifier(_)
1187 | Type::Mapping(_)
1188 | Type::Optional(_)
1189 | Type::String
1190 | Type::Address
1191 | Type::Signature
1192 | Type::Tuple(_) => {
1193 self.emit_err(TypeCheckerError::optional_wrapping_unsupported(inner, span));
1194 }
1195 _ => self.assert_type_is_valid(inner, span),
1196 }
1197 }
1198 _ => {} }
1200 }
1201
1202 pub fn assert_storage_type_is_valid(&mut self, type_: &Type, span: Span) {
1205 match type_ {
1206 Type::Unit => {
1208 self.emit_err(TypeCheckerError::invalid_storage_type("unit", span));
1209 }
1210 Type::String => {
1211 self.emit_err(TypeCheckerError::invalid_storage_type("string", span));
1212 }
1213 Type::Address => {
1214 self.emit_err(TypeCheckerError::invalid_storage_type("address", span));
1215 }
1216 Type::Signature => {
1217 self.emit_err(TypeCheckerError::invalid_storage_type("signature", span));
1218 }
1219 Type::Future(_) => {
1220 self.emit_err(TypeCheckerError::invalid_storage_type("future", span));
1221 }
1222 Type::Optional(_) => {
1223 self.emit_err(TypeCheckerError::invalid_storage_type("optional", span));
1224 }
1225 Type::Mapping(_) => {
1226 self.emit_err(TypeCheckerError::invalid_storage_type("mapping", span));
1227 }
1228 Type::Tuple(_) => {
1229 self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span));
1230 }
1231
1232 Type::Composite(struct_type) => {
1234 if let Some(struct_) = self.lookup_struct(
1235 struct_type.program.or(self.scope_state.program_name),
1236 &struct_type.path.absolute_path(),
1237 ) {
1238 if struct_.is_record {
1239 self.emit_err(TypeCheckerError::invalid_storage_type("record", span));
1240 return;
1241 }
1242
1243 for field in &struct_.members {
1245 self.assert_storage_type_is_valid(&field.type_, span);
1246 }
1247 } else {
1248 self.emit_err(TypeCheckerError::invalid_storage_type("undefined struct", span));
1249 }
1250 }
1251
1252 Type::Array(array_type) => {
1254 if let Some(length) = array_type.length.as_u32()
1255 && (length == 0 || length > self.limits.max_array_elements as u32)
1256 {
1257 self.emit_err(TypeCheckerError::invalid_storage_type("array", span));
1258 }
1259
1260 let element_ty = array_type.element_type();
1261 match element_ty {
1262 Type::Future(_) => self.emit_err(TypeCheckerError::invalid_storage_type("future", span)),
1263 Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span)),
1264 Type::Optional(_) => self.emit_err(TypeCheckerError::invalid_storage_type("optional", span)),
1265 _ => {}
1266 }
1267
1268 self.assert_storage_type_is_valid(element_ty, span);
1269 }
1270
1271 _ => {} }
1274 }
1275
1276 pub fn assert_mapping_type(&self, type_: &Type, span: Span) {
1278 if type_ != &Type::Err && !matches!(type_, Type::Mapping(_)) {
1279 self.emit_err(TypeCheckerError::type_should_be2(type_, "a mapping", span));
1280 }
1281 }
1282
1283 pub fn assert_optional_type(&self, type_: &Type, span: Span) {
1285 if type_ != &Type::Err && !matches!(type_, Type::Optional(_)) {
1286 self.emit_err(TypeCheckerError::type_should_be2(type_, "an optional", span));
1287 }
1288 }
1289
1290 pub fn assert_vector_type(&self, type_: &Type, span: Span) {
1292 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) {
1293 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector", span));
1294 }
1295 }
1296
1297 pub fn assert_vector_or_mapping_type(&self, type_: &Type, span: Span) {
1299 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) && !matches!(type_, Type::Mapping(_)) {
1300 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector or a mapping", span));
1301 }
1302 }
1303
1304 pub fn contains_optional_type(&mut self, ty: &Type) -> bool {
1305 let mut visited_paths = IndexSet::<Vec<Symbol>>::new();
1306 self.contains_optional_type_inner(ty, &mut visited_paths)
1307 }
1308
1309 fn contains_optional_type_inner(&mut self, ty: &Type, visited_paths: &mut IndexSet<Vec<Symbol>>) -> bool {
1310 match ty {
1311 Type::Optional(_) => true,
1312
1313 Type::Tuple(tuple) => tuple.elements.iter().any(|e| self.contains_optional_type_inner(e, visited_paths)),
1314
1315 Type::Array(array) => self.contains_optional_type_inner(&array.element_type, visited_paths),
1316
1317 Type::Composite(struct_type) => {
1318 let path = struct_type.path.absolute_path();
1319
1320 if !visited_paths.insert(path.clone()) {
1322 return false;
1323 }
1324
1325 if let Some(comp) = self.lookup_struct(struct_type.program.or(self.scope_state.program_name), &path) {
1326 comp.members
1327 .iter()
1328 .any(|Member { type_, .. }| self.contains_optional_type_inner(type_, visited_paths))
1329 } else {
1330 false
1331 }
1332 }
1333
1334 _ => false,
1335 }
1336 }
1337
1338 pub fn assert_array_type(&self, type_: &Type, span: Span) {
1339 if type_ != &Type::Err && !matches!(type_, Type::Array(_)) {
1340 self.emit_err(TypeCheckerError::type_should_be2(type_, "an array", span));
1341 }
1342 }
1343
1344 pub fn check_function_signature(&mut self, function: &Function, is_stub: bool) {
1346 let function_path = self
1347 .scope_state
1348 .module_name
1349 .iter()
1350 .cloned()
1351 .chain(std::iter::once(function.identifier.name))
1352 .collect::<Vec<Symbol>>();
1353
1354 self.scope_state.variant = Some(function.variant);
1355
1356 let mut inferred_inputs: Vec<Type> = Vec::new();
1357
1358 if self.scope_state.variant == Some(Variant::AsyncFunction) && !self.scope_state.is_stub {
1359 if !function.output.is_empty() {
1361 self.emit_err(TypeCheckerError::async_function_cannot_return_value(function.span()));
1362 }
1363
1364 let mut caller_finalizers = self
1367 .async_function_callers
1368 .get(&Location::new(self.scope_state.program_name.unwrap(), function_path))
1369 .map(|callers| {
1370 callers
1371 .iter()
1372 .flat_map(|caller| {
1373 let caller = Location::new(caller.program, caller.path.clone());
1374 self.state.symbol_table.lookup_function(&caller)
1375 })
1376 .flat_map(|fn_symbol| fn_symbol.finalizer.clone())
1377 })
1378 .into_iter()
1379 .flatten();
1380
1381 if let Some(first) = caller_finalizers.next() {
1382 inferred_inputs = first.inferred_inputs.clone();
1383
1384 for finalizer in caller_finalizers {
1387 assert_eq!(inferred_inputs.len(), finalizer.inferred_inputs.len());
1388 for (t1, t2) in inferred_inputs.iter_mut().zip(finalizer.inferred_inputs.iter()) {
1389 Self::merge_types(t1, t2);
1390 }
1391 }
1392 } else {
1393 self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
1394 function.identifier.name,
1395 function.span(),
1396 ));
1397 }
1398 }
1399
1400 if self.scope_state.variant != Some(Variant::Inline) && !function.const_parameters.is_empty() {
1403 self.emit_err(TypeCheckerError::only_inline_can_have_const_generics(function.identifier.span()));
1404 }
1405
1406 for const_param in &function.const_parameters {
1407 self.visit_type(const_param.type_());
1408
1409 if !matches!(
1411 const_param.type_(),
1412 Type::Boolean | Type::Integer(_) | Type::Address | Type::Scalar | Type::Group | Type::Field
1413 ) {
1414 self.emit_err(TypeCheckerError::bad_const_generic_type(const_param.type_(), const_param.span()));
1415 }
1416
1417 if let Err(err) = self.state.symbol_table.insert_variable(
1419 self.scope_state.program_name.unwrap(),
1420 &[const_param.identifier().name],
1421 VariableSymbol {
1422 type_: const_param.type_().clone(),
1423 span: const_param.identifier.span(),
1424 declaration: VariableType::ConstParameter,
1425 },
1426 ) {
1427 self.state.handler.emit_err(err);
1428 }
1429
1430 self.state.type_table.insert(const_param.identifier().id(), const_param.type_().clone());
1432 }
1433
1434 if function.input.len() > self.limits.max_inputs && function.variant != Variant::Inline {
1436 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_inputs(
1437 function.variant,
1438 function.identifier,
1439 self.limits.max_inputs,
1440 function.input.len(),
1441 function.identifier.span,
1442 ));
1443 }
1444
1445 for (i, input) in function.input.iter().enumerate() {
1447 self.visit_type(input.type_());
1448
1449 let table_type = inferred_inputs.get(i).unwrap_or_else(|| input.type_());
1451
1452 self.assert_type_is_valid(table_type, input.span());
1454
1455 if matches!(table_type, Type::Tuple(_)) {
1457 self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input.span()))
1458 }
1459
1460 if self.contains_optional_type(table_type)
1462 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1463 {
1464 self.emit_err(TypeCheckerError::function_cannot_take_option_as_input(
1465 input.identifier,
1466 table_type,
1467 input.span(),
1468 ))
1469 }
1470
1471 if let Type::Composite(struct_) = table_type {
1473 if !function.variant.is_transition() {
1475 if let Some(elem) = self
1476 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1477 {
1478 if elem.is_record {
1479 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input.span()))
1480 }
1481 } else {
1482 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), input.span()));
1483 }
1484 }
1485 }
1486
1487 match self.scope_state.variant.unwrap() {
1489 Variant::Transition | Variant::AsyncTransition if input.mode() == Mode::Constant => {
1491 self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input.span()))
1492 }
1493 Variant::Function | Variant::Inline if input.mode() != Mode::None => {
1495 self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input.span()))
1496 }
1497 Variant::AsyncFunction if matches!(input.mode(), Mode::Constant | Mode::Private) => {
1499 self.emit_err(TypeCheckerError::async_function_input_must_be_public(input.span()));
1500 }
1501 _ => {} }
1503
1504 if matches!(table_type, Type::Future(..)) {
1505 if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction)) {
1507 self.emit_err(TypeCheckerError::no_future_parameters(input.span()));
1508 }
1509 }
1510
1511 if !is_stub {
1512 if let Err(err) = self.state.symbol_table.insert_variable(
1514 self.scope_state.program_name.unwrap(),
1515 &[input.identifier().name],
1516 VariableSymbol {
1517 type_: table_type.clone(),
1518 span: input.identifier.span(),
1519 declaration: VariableType::Input(input.mode()),
1520 },
1521 ) {
1522 self.state.handler.emit_err(err);
1523 }
1524
1525 self.state.type_table.insert(input.identifier().id(), table_type.clone());
1527 }
1528 }
1529
1530 if function.output.len() > self.limits.max_outputs && function.variant != Variant::Inline {
1532 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_outputs(
1533 function.variant,
1534 function.identifier,
1535 self.limits.max_outputs,
1536 function.output.len(),
1537 function.identifier.span,
1538 ));
1539 }
1540
1541 function.output.iter().enumerate().for_each(|(index, function_output)| {
1544 self.visit_type(&function_output.type_);
1545
1546 if let Type::Composite(struct_) = function_output.type_.clone()
1549 && let Some(val) =
1550 self.lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1551 && val.is_record
1552 && !function.variant.is_transition()
1553 {
1554 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(function_output.span));
1555 }
1556
1557 self.assert_type_is_valid(&function_output.type_, function_output.span);
1559
1560 if matches!(&function_output.type_, Type::Tuple(_)) {
1562 self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
1563 }
1564
1565 if self.contains_optional_type(&function_output.type_)
1567 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1568 {
1569 self.emit_err(TypeCheckerError::function_cannot_return_option_as_output(
1570 &function_output.type_,
1571 function_output.span(),
1572 ))
1573 }
1574
1575 if function_output.mode == Mode::Constant {
1578 self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
1579 }
1580 if self.scope_state.variant == Some(Variant::AsyncTransition)
1582 && ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
1583 || (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
1584 {
1585 self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
1586 }
1587 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script))
1589 && matches!(function_output.type_, Type::Future(_))
1590 {
1591 self.emit_err(TypeCheckerError::only_async_transition_can_return_future(function_output.span));
1592 }
1593 });
1594
1595 self.visit_type(&function.output_type);
1596 }
1597
1598 fn merge_types(lhs: &mut Type, rhs: &Type) {
1604 if let Type::Future(f1) = lhs {
1605 if let Type::Future(f2) = rhs {
1606 for (i, type_) in f2.inputs.iter().enumerate() {
1607 if let Some(lhs_type) = f1.inputs.get_mut(i) {
1608 Self::merge_types(lhs_type, type_);
1609 } else {
1610 f1.inputs.push(Type::Err);
1611 }
1612 }
1613 } else {
1614 *lhs = Type::Err;
1615 }
1616 } else if !lhs.eq_user(rhs) {
1617 *lhs = Type::Err;
1618 }
1619 }
1620
1621 pub fn lookup_struct(&mut self, program: Option<Symbol>, name: &[Symbol]) -> Option<Composite> {
1623 let record_comp =
1624 program.and_then(|prog| self.state.symbol_table.lookup_record(&Location::new(prog, name.to_vec())));
1625 let comp = record_comp.or_else(|| self.state.symbol_table.lookup_struct(name));
1626 if let Some(s) = comp {
1628 if !s.is_record || program == self.scope_state.program_name {
1630 self.used_structs.insert(name.to_vec());
1631 }
1632 }
1633 comp.cloned()
1634 }
1635
1636 pub fn insert_variable(&mut self, inferred_type: Option<Type>, name: &Identifier, type_: Type, span: Span) {
1638 self.insert_symbol_conditional_scope(name.name);
1639
1640 let is_future = match &type_ {
1641 Type::Future(..) => true,
1642 Type::Tuple(tuple_type) if matches!(tuple_type.elements().last(), Some(Type::Future(..))) => true,
1643 _ => false,
1644 };
1645
1646 if is_future {
1647 if let Some(call_location) = &self.scope_state.call_location {
1650 self.scope_state.futures.insert(name.name, call_location.clone());
1651 }
1652 }
1653
1654 let ty = match (is_future, inferred_type) {
1655 (false, _) => type_,
1656 (true, Some(inferred)) => inferred,
1657 (true, None) => unreachable!("Type checking guarantees the inferred type is present"),
1658 };
1659
1660 if let Err(err) = self.state.symbol_table.insert_variable(
1662 self.scope_state.program_name.unwrap(),
1663 &[name.name],
1664 VariableSymbol { type_: ty.clone(), span, declaration: VariableType::Mut },
1665 ) {
1666 self.state.handler.emit_err(err);
1667 }
1668 }
1669
1670 pub fn check_access_allowed(&mut self, name: &str, finalize_op: bool, span: Span) {
1674 if self.scope_state.variant == Some(Variant::AsyncFunction) && !finalize_op {
1676 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_finalize(name, span));
1677 }
1678 else if self.async_block_id.is_some() && !finalize_op {
1680 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_async_block(name, span));
1681 }
1682 else if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
1684 && self.async_block_id.is_none()
1685 && finalize_op
1686 {
1687 self.state.handler.emit_err(TypeCheckerError::invalid_operation_outside_finalize(name, span));
1688 }
1689 }
1690
1691 pub fn is_external_record(&self, ty: &Type) -> bool {
1692 if let Type::Composite(typ) = &ty {
1693 let this_program = self.scope_state.program_name.unwrap();
1694 let program = typ.program.unwrap_or(this_program);
1695 program != this_program
1696 && self
1697 .state
1698 .symbol_table
1699 .lookup_record(&Location::new(program, typ.path.absolute_path().to_vec()))
1700 .is_some()
1701 } else {
1702 false
1703 }
1704 }
1705
1706 pub fn parse_integer_literal<I: FromStrRadix>(&self, raw_string: &str, span: Span, type_string: &str) {
1707 let string = raw_string.replace('_', "");
1708 if I::from_str_by_radix(&string).is_err() {
1709 self.state.handler.emit_err(TypeCheckerError::invalid_int_value(string, type_string, span));
1710 }
1711 }
1712
1713 pub fn emit_inference_failure_error(&self, ty: &mut Type, expr: &Expression) {
1716 self.emit_err(TypeCheckerError::could_not_determine_type(expr.clone(), expr.span()));
1717 *ty = Type::Err;
1718 self.state.type_table.insert(expr.id(), Type::Err);
1719 }
1720
1721 pub fn check_numeric_literal(&self, input: &Literal, ty: &Type) -> bool {
1724 if let Literal { variant: LiteralVariant::Unsuffixed(s), .. } = input {
1725 let span = input.span();
1726 let has_nondecimal_prefix =
1727 |s: &str| ["0x", "0o", "0b", "-0x", "-0o", "-0b"].iter().any(|p| s.starts_with(p));
1728
1729 macro_rules! parse_int {
1730 ($t:ty, $name:expr) => {
1731 self.parse_integer_literal::<$t>(s, span, $name)
1732 };
1733 }
1734
1735 match ty {
1736 Type::Integer(kind) => match kind {
1737 IntegerType::U8 => parse_int!(u8, "u8"),
1738 IntegerType::U16 => parse_int!(u16, "u16"),
1739 IntegerType::U32 => parse_int!(u32, "u32"),
1740 IntegerType::U64 => parse_int!(u64, "u64"),
1741 IntegerType::U128 => parse_int!(u128, "u128"),
1742 IntegerType::I8 => parse_int!(i8, "i8"),
1743 IntegerType::I16 => parse_int!(i16, "i16"),
1744 IntegerType::I32 => parse_int!(i32, "i32"),
1745 IntegerType::I64 => parse_int!(i64, "i64"),
1746 IntegerType::I128 => parse_int!(i128, "i128"),
1747 },
1748 Type::Group => {
1749 if has_nondecimal_prefix(s) {
1750 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1752 return false;
1753 } else {
1754 let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1755 if !trimmed.is_empty()
1756 && format!("{trimmed}group")
1757 .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1758 .is_err()
1759 {
1760 self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1761 return false;
1762 }
1763 }
1764 }
1765 Type::Field | Type::Scalar => {
1766 if has_nondecimal_prefix(s) {
1767 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1769 return false;
1770 }
1771 }
1772 _ => {
1773 }
1775 }
1776 }
1777 true
1778 }
1779}