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::CheatCodeSetBlockTimestamp => {
1057 self.assert_type(&arguments[0].0, &Type::Integer(IntegerType::I64), arguments[0].1.span());
1058 Type::Unit
1059 }
1060 CoreFunction::CheatCodeSetSigner => {
1061 self.assert_type(&arguments[0].0, &Type::String, arguments[0].1.span());
1063 if let Expression::Literal(Literal { variant: LiteralVariant::String(s), .. }) = arguments[0].1 {
1065 let s = s.replace("\"", "");
1066 let is_err = match self.state.network {
1067 NetworkName::TestnetV0 => PrivateKey::<TestnetV0>::from_str(&s).is_err(),
1068 NetworkName::MainnetV0 => PrivateKey::<MainnetV0>::from_str(&s).is_err(),
1069 NetworkName::CanaryV0 => PrivateKey::<CanaryV0>::from_str(&s).is_err(),
1070 };
1071 if is_err {
1072 self.emit_err(TypeCheckerError::custom(
1073 "`CheatCode::set_signer` must be called with a valid private key",
1074 arguments[0].1.span(),
1075 ));
1076 }
1077 };
1078 Type::Unit
1079 }
1080 }
1081 }
1082
1083 pub fn assert_member_is_not_record(&mut self, span: Span, parent: Symbol, type_: &Type) {
1085 match type_ {
1086 Type::Composite(struct_)
1087 if self
1088 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1089 .is_some_and(|struct_| struct_.is_record) =>
1090 {
1091 self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(
1092 parent,
1093 struct_.path.clone(),
1094 span,
1095 ))
1096 }
1097 Type::Tuple(tuple_type) => {
1098 for type_ in tuple_type.elements().iter() {
1099 self.assert_member_is_not_record(span, parent, type_)
1100 }
1101 }
1102 _ => {} }
1104 }
1105
1106 pub fn assert_type_is_valid(&mut self, type_: &Type, span: Span) {
1108 match type_ {
1109 Type::Unit => {
1111 self.emit_err(TypeCheckerError::unit_type_only_return(span));
1112 }
1113 Type::String => {
1115 self.emit_err(TypeCheckerError::strings_are_not_supported(span));
1116 }
1117 Type::Composite(struct_)
1119 if self
1120 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1121 .is_none() =>
1122 {
1123 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), span));
1124 }
1125 Type::Tuple(tuple_type) => {
1127 for type_ in tuple_type.elements().iter() {
1128 self.assert_type_is_valid(type_, span);
1129 }
1130 }
1131 Type::Mapping(mapping_type) => {
1133 self.assert_type_is_valid(&mapping_type.key, span);
1134 self.assert_type_is_valid(&mapping_type.value, span);
1135 }
1136 Type::Array(array_type) => {
1138 if let Some(length) = array_type.length.as_u32() {
1141 if length > self.limits.max_array_elements as u32 {
1142 self.emit_err(TypeCheckerError::array_too_large(length, self.limits.max_array_elements, span));
1143 }
1144 } else if let Expression::Literal(_) = &*array_type.length {
1145 self.emit_err(TypeCheckerError::array_too_large_for_u32(span));
1147 }
1148 match array_type.element_type() {
1152 Type::Future(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_future(span)),
1154 Type::Tuple(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span)),
1156 Type::Composite(struct_type) => {
1158 if let Some(struct_) = self.lookup_struct(
1160 struct_type.program.or(self.scope_state.program_name),
1161 &struct_type.path.absolute_path(),
1162 ) {
1163 if struct_.is_record {
1165 self.emit_err(TypeCheckerError::array_element_cannot_be_record(span));
1166 }
1167 }
1168 }
1169 _ => {} }
1171 self.assert_type_is_valid(array_type.element_type(), span);
1172 }
1173
1174 Type::Optional(OptionalType { inner }) => {
1175 if self.disallowed_inside_optional(inner) {
1177 self.emit_err(TypeCheckerError::optional_wrapping_unsupported(inner, span));
1178 }
1179
1180 self.assert_type_is_valid(inner, span);
1182 }
1183
1184 Type::Address
1185 | Type::Boolean
1186 | Type::Composite(_)
1187 | Type::Field
1188 | Type::Future(_)
1189 | Type::Group
1190 | Type::Identifier(_)
1191 | Type::Integer(_)
1192 | Type::Scalar
1193 | Type::Signature
1194 | Type::Vector(_)
1195 | Type::Numeric
1196 | Type::Err => {} }
1198 }
1199
1200 fn disallowed_inside_optional(&mut self, ty: &Type) -> bool {
1202 match ty {
1203 Type::Unit
1204 | Type::Err
1205 | Type::Future(_)
1206 | Type::Identifier(_)
1207 | Type::Mapping(_)
1208 | Type::Optional(_)
1209 | Type::String
1210 | Type::Signature
1211 | Type::Tuple(_)
1212 | Type::Vector(_) => true,
1213
1214 Type::Composite(struct_type) => {
1215 if let Some(struct_) = self.lookup_struct(
1216 struct_type.program.or(self.scope_state.program_name),
1217 &struct_type.path.absolute_path(),
1218 ) {
1219 if struct_.is_record {
1220 return true;
1221 }
1222
1223 for field in &struct_.members {
1225 let field_ty = &field.type_;
1226 let ty_to_check = match field_ty {
1228 Type::Optional(OptionalType { inner }) => inner,
1229 _ => field_ty,
1230 };
1231 if self.disallowed_inside_optional(ty_to_check) {
1232 return true;
1233 }
1234 }
1235 }
1236 false
1237 }
1238
1239 Type::Array(array_type) => {
1240 let elem_type = match array_type.element_type() {
1241 Type::Optional(OptionalType { inner }) => inner,
1242 other => other,
1243 };
1244 self.disallowed_inside_optional(elem_type)
1245 }
1246
1247 Type::Address
1248 | Type::Boolean
1249 | Type::Field
1250 | Type::Group
1251 | Type::Integer(_)
1252 | Type::Numeric
1253 | Type::Scalar => false,
1254 }
1255 }
1256
1257 pub fn assert_storage_type_is_valid(&mut self, type_: &Type, span: Span) {
1260 if type_.is_empty() {
1261 self.emit_err(TypeCheckerError::invalid_storage_type("A zero sized type", span));
1262 }
1263 match type_ {
1264 Type::Unit => {
1266 self.emit_err(TypeCheckerError::invalid_storage_type("unit", span));
1267 }
1268 Type::String => {
1269 self.emit_err(TypeCheckerError::invalid_storage_type("string", span));
1270 }
1271 Type::Signature => {
1272 self.emit_err(TypeCheckerError::invalid_storage_type("signature", span));
1273 }
1274 Type::Future(_) => {
1275 self.emit_err(TypeCheckerError::invalid_storage_type("future", span));
1276 }
1277 Type::Optional(_) => {
1278 self.emit_err(TypeCheckerError::invalid_storage_type("optional", span));
1279 }
1280 Type::Mapping(_) => {
1281 self.emit_err(TypeCheckerError::invalid_storage_type("mapping", span));
1282 }
1283 Type::Tuple(_) => {
1284 self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span));
1285 }
1286
1287 Type::Composite(struct_type) => {
1289 if let Some(struct_) = self.lookup_struct(
1290 struct_type.program.or(self.scope_state.program_name),
1291 &struct_type.path.absolute_path(),
1292 ) {
1293 if struct_.is_record {
1294 self.emit_err(TypeCheckerError::invalid_storage_type("record", span));
1295 return;
1296 }
1297
1298 for field in &struct_.members {
1300 self.assert_storage_type_is_valid(&field.type_, span);
1301 }
1302 } else {
1303 self.emit_err(TypeCheckerError::invalid_storage_type("undefined struct", span));
1304 }
1305 }
1306
1307 Type::Array(array_type) => {
1309 if let Some(length) = array_type.length.as_u32()
1310 && (length == 0 || length > self.limits.max_array_elements as u32)
1311 {
1312 self.emit_err(TypeCheckerError::invalid_storage_type("array", span));
1313 }
1314
1315 let element_ty = array_type.element_type();
1316 match element_ty {
1317 Type::Future(_) => self.emit_err(TypeCheckerError::invalid_storage_type("future", span)),
1318 Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span)),
1319 Type::Optional(_) => self.emit_err(TypeCheckerError::invalid_storage_type("optional", span)),
1320 _ => {}
1321 }
1322
1323 self.assert_storage_type_is_valid(element_ty, span);
1324 }
1325
1326 Type::Address
1328 | Type::Boolean
1329 | Type::Field
1330 | Type::Group
1331 | Type::Identifier(_)
1332 | Type::Integer(_)
1333 | Type::Scalar
1334 | Type::Numeric
1335 | Type::Err
1336 | Type::Vector(_) => {} }
1338 }
1339
1340 pub fn assert_mapping_type(&self, type_: &Type, span: Span) {
1342 if type_ != &Type::Err && !matches!(type_, Type::Mapping(_)) {
1343 self.emit_err(TypeCheckerError::type_should_be2(type_, "a mapping", span));
1344 }
1345 }
1346
1347 pub fn assert_optional_type(&self, type_: &Type, span: Span) {
1349 if type_ != &Type::Err && !matches!(type_, Type::Optional(_)) {
1350 self.emit_err(TypeCheckerError::type_should_be2(type_, "an optional", span));
1351 }
1352 }
1353
1354 pub fn assert_vector_type(&self, type_: &Type, span: Span) {
1356 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) {
1357 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector", span));
1358 }
1359 }
1360
1361 pub fn assert_vector_or_mapping_type(&self, type_: &Type, span: Span) {
1363 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) && !matches!(type_, Type::Mapping(_)) {
1364 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector or a mapping", span));
1365 }
1366 }
1367
1368 pub fn contains_optional_type(&mut self, ty: &Type) -> bool {
1369 let mut visited_paths = IndexSet::<Vec<Symbol>>::new();
1370 self.contains_optional_type_inner(ty, &mut visited_paths)
1371 }
1372
1373 fn contains_optional_type_inner(&mut self, ty: &Type, visited_paths: &mut IndexSet<Vec<Symbol>>) -> bool {
1374 match ty {
1375 Type::Optional(_) => true,
1376
1377 Type::Tuple(tuple) => tuple.elements.iter().any(|e| self.contains_optional_type_inner(e, visited_paths)),
1378
1379 Type::Array(array) => self.contains_optional_type_inner(&array.element_type, visited_paths),
1380
1381 Type::Composite(struct_type) => {
1382 let path = struct_type.path.absolute_path();
1383
1384 if !visited_paths.insert(path.clone()) {
1386 return false;
1387 }
1388
1389 if let Some(comp) = self.lookup_struct(struct_type.program.or(self.scope_state.program_name), &path) {
1390 comp.members
1391 .iter()
1392 .any(|Member { type_, .. }| self.contains_optional_type_inner(type_, visited_paths))
1393 } else {
1394 false
1395 }
1396 }
1397
1398 _ => false,
1399 }
1400 }
1401
1402 pub fn assert_array_type(&self, type_: &Type, span: Span) {
1403 if type_ != &Type::Err && !matches!(type_, Type::Array(_)) {
1404 self.emit_err(TypeCheckerError::type_should_be2(type_, "an array", span));
1405 }
1406 }
1407
1408 pub fn check_function_signature(&mut self, function: &Function, is_stub: bool) {
1410 let function_path = self
1411 .scope_state
1412 .module_name
1413 .iter()
1414 .cloned()
1415 .chain(std::iter::once(function.identifier.name))
1416 .collect::<Vec<Symbol>>();
1417
1418 self.scope_state.variant = Some(function.variant);
1419
1420 let mut inferred_inputs: Vec<Type> = Vec::new();
1421
1422 if self.scope_state.variant == Some(Variant::AsyncFunction) && !self.scope_state.is_stub {
1423 if !function.output.is_empty() {
1425 self.emit_err(TypeCheckerError::async_function_cannot_return_value(function.span()));
1426 }
1427
1428 let mut caller_finalizers = self
1431 .async_function_callers
1432 .get(&Location::new(self.scope_state.program_name.unwrap(), function_path))
1433 .map(|callers| {
1434 callers
1435 .iter()
1436 .flat_map(|caller| {
1437 let caller = Location::new(caller.program, caller.path.clone());
1438 self.state.symbol_table.lookup_function(&caller)
1439 })
1440 .flat_map(|fn_symbol| fn_symbol.finalizer.clone())
1441 })
1442 .into_iter()
1443 .flatten();
1444
1445 if let Some(first) = caller_finalizers.next() {
1446 inferred_inputs = first.inferred_inputs.clone();
1447
1448 for finalizer in caller_finalizers {
1451 assert_eq!(inferred_inputs.len(), finalizer.inferred_inputs.len());
1452 for (t1, t2) in inferred_inputs.iter_mut().zip(finalizer.inferred_inputs.iter()) {
1453 Self::merge_types(t1, t2);
1454 }
1455 }
1456 } else {
1457 self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
1458 function.identifier.name,
1459 function.span(),
1460 ));
1461 }
1462 }
1463
1464 if self.scope_state.variant != Some(Variant::Inline) && !function.const_parameters.is_empty() {
1467 self.emit_err(TypeCheckerError::only_inline_can_have_const_generics(function.identifier.span()));
1468 }
1469
1470 for const_param in &function.const_parameters {
1471 self.visit_type(const_param.type_());
1472
1473 if !matches!(
1475 const_param.type_(),
1476 Type::Boolean | Type::Integer(_) | Type::Address | Type::Scalar | Type::Group | Type::Field
1477 ) {
1478 self.emit_err(TypeCheckerError::bad_const_generic_type(const_param.type_(), const_param.span()));
1479 }
1480
1481 if let Err(err) = self.state.symbol_table.insert_variable(
1483 self.scope_state.program_name.unwrap(),
1484 &[const_param.identifier().name],
1485 VariableSymbol {
1486 type_: const_param.type_().clone(),
1487 span: const_param.identifier.span(),
1488 declaration: VariableType::ConstParameter,
1489 },
1490 ) {
1491 self.state.handler.emit_err(err);
1492 }
1493
1494 self.state.type_table.insert(const_param.identifier().id(), const_param.type_().clone());
1496 }
1497
1498 if function.input.len() > self.limits.max_inputs && function.variant != Variant::Inline {
1500 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_inputs(
1501 function.variant,
1502 function.identifier,
1503 self.limits.max_inputs,
1504 function.input.len(),
1505 function.identifier.span,
1506 ));
1507 }
1508
1509 for (i, input) in function.input.iter().enumerate() {
1511 self.visit_type(input.type_());
1512
1513 let table_type = inferred_inputs.get(i).unwrap_or_else(|| input.type_());
1515
1516 self.assert_type_is_valid(table_type, input.span());
1518
1519 if matches!(table_type, Type::Tuple(_)) {
1521 self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input.span()))
1522 }
1523
1524 if self.contains_optional_type(table_type)
1526 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1527 {
1528 self.emit_err(TypeCheckerError::function_cannot_take_option_as_input(
1529 input.identifier,
1530 table_type,
1531 input.span(),
1532 ))
1533 }
1534
1535 if let Type::Composite(struct_) = table_type {
1537 if !function.variant.is_transition() {
1539 if let Some(elem) = self
1540 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1541 {
1542 if elem.is_record {
1543 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input.span()))
1544 }
1545 } else {
1546 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), input.span()));
1547 }
1548 }
1549 }
1550
1551 match self.scope_state.variant.unwrap() {
1553 Variant::Transition | Variant::AsyncTransition if input.mode() == Mode::Constant => {
1555 self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input.span()))
1556 }
1557 Variant::Function | Variant::Inline if input.mode() != Mode::None => {
1559 self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input.span()))
1560 }
1561 Variant::AsyncFunction if matches!(input.mode(), Mode::Constant | Mode::Private) => {
1563 self.emit_err(TypeCheckerError::async_function_input_must_be_public(input.span()));
1564 }
1565 _ => {} }
1567
1568 if matches!(table_type, Type::Future(..)) {
1569 if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction)) {
1571 self.emit_err(TypeCheckerError::no_future_parameters(input.span()));
1572 }
1573 }
1574
1575 if !is_stub {
1576 if let Err(err) = self.state.symbol_table.insert_variable(
1578 self.scope_state.program_name.unwrap(),
1579 &[input.identifier().name],
1580 VariableSymbol {
1581 type_: table_type.clone(),
1582 span: input.identifier.span(),
1583 declaration: VariableType::Input(input.mode()),
1584 },
1585 ) {
1586 self.state.handler.emit_err(err);
1587 }
1588
1589 self.state.type_table.insert(input.identifier().id(), table_type.clone());
1591 }
1592 }
1593
1594 if function.output.len() > self.limits.max_outputs && function.variant != Variant::Inline {
1596 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_outputs(
1597 function.variant,
1598 function.identifier,
1599 self.limits.max_outputs,
1600 function.output.len(),
1601 function.identifier.span,
1602 ));
1603 }
1604
1605 function.output.iter().enumerate().for_each(|(index, function_output)| {
1608 self.visit_type(&function_output.type_);
1609
1610 if let Type::Composite(struct_) = function_output.type_.clone()
1613 && let Some(val) =
1614 self.lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1615 && val.is_record
1616 && !function.variant.is_transition()
1617 {
1618 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(function_output.span));
1619 }
1620
1621 self.assert_type_is_valid(&function_output.type_, function_output.span);
1623
1624 if matches!(&function_output.type_, Type::Tuple(_)) {
1626 self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
1627 }
1628
1629 if self.contains_optional_type(&function_output.type_)
1631 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1632 {
1633 self.emit_err(TypeCheckerError::function_cannot_return_option_as_output(
1634 &function_output.type_,
1635 function_output.span(),
1636 ))
1637 }
1638
1639 if function_output.mode == Mode::Constant {
1642 self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
1643 }
1644 if self.scope_state.variant == Some(Variant::AsyncTransition)
1646 && ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
1647 || (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
1648 {
1649 self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
1650 }
1651 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script))
1653 && matches!(function_output.type_, Type::Future(_))
1654 {
1655 self.emit_err(TypeCheckerError::only_async_transition_can_return_future(function_output.span));
1656 }
1657 });
1658
1659 self.visit_type(&function.output_type);
1660 }
1661
1662 fn merge_types(lhs: &mut Type, rhs: &Type) {
1668 if let Type::Future(f1) = lhs {
1669 if let Type::Future(f2) = rhs {
1670 for (i, type_) in f2.inputs.iter().enumerate() {
1671 if let Some(lhs_type) = f1.inputs.get_mut(i) {
1672 Self::merge_types(lhs_type, type_);
1673 } else {
1674 f1.inputs.push(Type::Err);
1675 }
1676 }
1677 } else {
1678 *lhs = Type::Err;
1679 }
1680 } else if !lhs.eq_user(rhs) {
1681 *lhs = Type::Err;
1682 }
1683 }
1684
1685 pub fn lookup_struct(&mut self, program: Option<Symbol>, name: &[Symbol]) -> Option<Composite> {
1687 let record_comp =
1688 program.and_then(|prog| self.state.symbol_table.lookup_record(&Location::new(prog, name.to_vec())));
1689 let comp = record_comp.or_else(|| self.state.symbol_table.lookup_struct(name));
1690 if let Some(s) = comp {
1692 if !s.is_record || program == self.scope_state.program_name {
1694 self.used_structs.insert(name.to_vec());
1695 }
1696 }
1697 comp.cloned()
1698 }
1699
1700 pub fn insert_variable(&mut self, inferred_type: Option<Type>, name: &Identifier, type_: Type, span: Span) {
1702 self.insert_symbol_conditional_scope(name.name);
1703
1704 let is_future = match &type_ {
1705 Type::Future(..) => true,
1706 Type::Tuple(tuple_type) if matches!(tuple_type.elements().last(), Some(Type::Future(..))) => true,
1707 _ => false,
1708 };
1709
1710 if is_future {
1711 if let Some(call_location) = &self.scope_state.call_location {
1714 self.scope_state.futures.insert(name.name, call_location.clone());
1715 }
1716 }
1717
1718 let ty = match (is_future, inferred_type) {
1719 (false, _) => type_,
1720 (true, Some(inferred)) => inferred,
1721 (true, None) => unreachable!("Type checking guarantees the inferred type is present"),
1722 };
1723
1724 if let Err(err) = self.state.symbol_table.insert_variable(
1726 self.scope_state.program_name.unwrap(),
1727 &[name.name],
1728 VariableSymbol { type_: ty.clone(), span, declaration: VariableType::Mut },
1729 ) {
1730 self.state.handler.emit_err(err);
1731 }
1732 }
1733
1734 pub fn check_access_allowed(&mut self, name: &str, finalize_op: bool, span: Span) {
1738 if self.scope_state.variant == Some(Variant::AsyncFunction) && !finalize_op {
1740 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_finalize(name, span));
1741 }
1742 else if self.async_block_id.is_some() && !finalize_op {
1744 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_async_block(name, span));
1745 }
1746 else if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
1748 && self.async_block_id.is_none()
1749 && finalize_op
1750 {
1751 self.state.handler.emit_err(TypeCheckerError::invalid_operation_outside_finalize(name, span));
1752 }
1753 }
1754
1755 pub fn is_external_record(&self, ty: &Type) -> bool {
1756 if let Type::Composite(typ) = &ty {
1757 let this_program = self.scope_state.program_name.unwrap();
1758 let program = typ.program.unwrap_or(this_program);
1759 program != this_program
1760 && self
1761 .state
1762 .symbol_table
1763 .lookup_record(&Location::new(program, typ.path.absolute_path().to_vec()))
1764 .is_some()
1765 } else {
1766 false
1767 }
1768 }
1769
1770 pub fn parse_integer_literal<I: FromStrRadix>(&self, raw_string: &str, span: Span, type_string: &str) {
1771 let string = raw_string.replace('_', "");
1772 if I::from_str_by_radix(&string).is_err() {
1773 self.state.handler.emit_err(TypeCheckerError::invalid_int_value(string, type_string, span));
1774 }
1775 }
1776
1777 pub fn emit_inference_failure_error(&self, ty: &mut Type, expr: &Expression) {
1780 self.emit_err(TypeCheckerError::could_not_determine_type(expr.clone(), expr.span()));
1781 *ty = Type::Err;
1782 self.state.type_table.insert(expr.id(), Type::Err);
1783 }
1784
1785 pub fn check_numeric_literal(&self, input: &Literal, ty: &Type) -> bool {
1788 if let Literal { variant: LiteralVariant::Unsuffixed(s), .. } = input {
1789 let span = input.span();
1790 let has_nondecimal_prefix =
1791 |s: &str| ["0x", "0o", "0b", "-0x", "-0o", "-0b"].iter().any(|p| s.starts_with(p));
1792
1793 macro_rules! parse_int {
1794 ($t:ty, $name:expr) => {
1795 self.parse_integer_literal::<$t>(s, span, $name)
1796 };
1797 }
1798
1799 match ty {
1800 Type::Integer(kind) => match kind {
1801 IntegerType::U8 => parse_int!(u8, "u8"),
1802 IntegerType::U16 => parse_int!(u16, "u16"),
1803 IntegerType::U32 => parse_int!(u32, "u32"),
1804 IntegerType::U64 => parse_int!(u64, "u64"),
1805 IntegerType::U128 => parse_int!(u128, "u128"),
1806 IntegerType::I8 => parse_int!(i8, "i8"),
1807 IntegerType::I16 => parse_int!(i16, "i16"),
1808 IntegerType::I32 => parse_int!(i32, "i32"),
1809 IntegerType::I64 => parse_int!(i64, "i64"),
1810 IntegerType::I128 => parse_int!(i128, "i128"),
1811 },
1812 Type::Group => {
1813 if has_nondecimal_prefix(s) {
1814 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1816 return false;
1817 } else {
1818 let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1819 if !trimmed.is_empty()
1820 && format!("{trimmed}group")
1821 .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1822 .is_err()
1823 {
1824 self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1825 return false;
1826 }
1827 }
1828 }
1829 Type::Field | Type::Scalar => {
1830 if has_nondecimal_prefix(s) {
1831 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1833 return false;
1834 }
1835 }
1836 _ => {
1837 }
1839 }
1840 }
1841 true
1842 }
1843}