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 assert_int_type(&self, type_: &Type, span: Span) {
133 if !matches!(type_, Type::Err | Type::Integer(_)) {
134 self.emit_err(TypeCheckerError::type_should_be2(type_, "an integer", span));
135 }
136 }
137
138 pub fn assert_unsigned_type(&self, type_: &Type, span: Span) {
139 if !matches!(
140 type_,
141 Type::Err
142 | Type::Integer(IntegerType::U8)
143 | Type::Integer(IntegerType::U16)
144 | Type::Integer(IntegerType::U32)
145 | Type::Integer(IntegerType::U64)
146 | Type::Integer(IntegerType::U128)
147 ) {
148 self.emit_err(TypeCheckerError::type_should_be2(type_, "an unsigned integer", span));
149 }
150 }
151
152 pub fn assert_bool_int_type(&self, type_: &Type, span: Span) {
153 if !matches!(
154 type_,
155 Type::Err
156 | Type::Boolean
157 | Type::Integer(IntegerType::U8)
158 | Type::Integer(IntegerType::U16)
159 | Type::Integer(IntegerType::U32)
160 | Type::Integer(IntegerType::U64)
161 | Type::Integer(IntegerType::U128)
162 | Type::Integer(IntegerType::I8)
163 | Type::Integer(IntegerType::I16)
164 | Type::Integer(IntegerType::I32)
165 | Type::Integer(IntegerType::I64)
166 | Type::Integer(IntegerType::I128)
167 ) {
168 self.emit_err(TypeCheckerError::type_should_be2(type_, "a bool or integer", span));
169 }
170 }
171
172 pub fn assert_field_int_type(&self, type_: &Type, span: Span) {
173 if !matches!(
174 type_,
175 Type::Err
176 | Type::Field
177 | Type::Integer(IntegerType::U8)
178 | Type::Integer(IntegerType::U16)
179 | Type::Integer(IntegerType::U32)
180 | Type::Integer(IntegerType::U64)
181 | Type::Integer(IntegerType::U128)
182 | Type::Integer(IntegerType::I8)
183 | Type::Integer(IntegerType::I16)
184 | Type::Integer(IntegerType::I32)
185 | Type::Integer(IntegerType::I64)
186 | Type::Integer(IntegerType::I128)
187 ) {
188 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field or integer", span));
189 }
190 }
191
192 pub fn assert_field_group_int_type(&self, type_: &Type, span: Span) {
193 if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Integer(_)) {
194 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, group, or integer", span));
195 }
196 }
197
198 pub fn get_intrinsic(&self, intrinsic_expr: &IntrinsicExpression) -> Option<Intrinsic> {
200 match Intrinsic::from_symbol(intrinsic_expr.name, &intrinsic_expr.type_parameters) {
202 None => {
203 self.emit_err(TypeCheckerError::invalid_intrinsic(intrinsic_expr.name, intrinsic_expr.span()));
205 None
206 }
207 intrinsic @ Some(Intrinsic::Deserialize(_, _)) => intrinsic,
208 Some(intrinsic) => {
209 if !intrinsic_expr.type_parameters.is_empty() {
211 self.emit_err(TypeCheckerError::custom(
212 format!("The intrinsic `{}` cannot have type parameters.", intrinsic_expr.name),
213 intrinsic_expr.span(),
214 ));
215 return None;
216 };
217
218 Some(intrinsic)
219 }
220 }
221 }
222
223 pub fn check_intrinsic(
227 &mut self,
228 intrinsic: Intrinsic,
229 arguments: &[Expression],
230 expected: &Option<Type>,
231 function_span: Span,
232 ) -> Type {
233 if arguments.len() != intrinsic.num_args() {
235 self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
236 intrinsic.num_args(),
237 arguments.len(),
238 function_span,
239 ));
240 return Type::Err;
241 }
242
243 let arguments = match intrinsic {
254 Intrinsic::OptionalUnwrap => {
255 let [opt] = arguments else { panic!("number of arguments is already checked") };
257
258 let opt_ty = if let Some(expected) = expected {
260 self.visit_expression(
261 opt,
262 &Some(Type::Optional(OptionalType { inner: Box::new(expected.clone()) })),
263 )
264 } else {
265 self.visit_expression(opt, &None)
266 };
267
268 vec![(opt_ty, opt)]
269 }
270
271 Intrinsic::OptionalUnwrapOr => {
272 let [opt, fallback] = arguments else { panic!("number of arguments is already checked") };
274
275 if let Some(expected) = expected {
276 let opt_ty = self.visit_expression(
278 opt,
279 &Some(Type::Optional(OptionalType { inner: Box::new(expected.clone()) })),
280 );
281 let fallback_ty = self.visit_expression(fallback, &Some(expected.clone()));
282 vec![(opt_ty, opt), (fallback_ty, fallback)]
283 } else {
284 let opt_ty = self.visit_expression(opt, &None);
286 let fallback_ty = if let Type::Optional(OptionalType { inner }) = &opt_ty {
287 self.visit_expression(fallback, &Some(*inner.clone()))
288 } else {
289 self.visit_expression(fallback, &None)
290 };
291 vec![(opt_ty, opt), (fallback_ty, fallback)]
292 }
293 }
294
295 Intrinsic::Get => {
297 let [container, key_or_index] = arguments else { panic!("number of arguments is already checked") };
298
299 let container_ty = self.visit_expression(container, &None);
300
301 let key_or_index_ty = match container_ty {
303 Type::Vector(_) => self.visit_expression_infer_default_u32(key_or_index),
304 Type::Mapping(MappingType { ref key, .. }) => {
305 self.visit_expression(key_or_index, &Some(*key.clone()))
306 }
307 _ => self.visit_expression(key_or_index, &None),
308 };
309
310 vec![(container_ty, container), (key_or_index_ty, key_or_index)]
311 }
312
313 Intrinsic::Set => {
315 let [container, key_or_index, val] = arguments else {
316 panic!("number of arguments is already checked")
317 };
318
319 let container_ty = self.visit_expression(container, &None);
320
321 let key_or_index_ty = match container_ty {
322 Type::Vector(_) => self.visit_expression_infer_default_u32(key_or_index),
323 Type::Mapping(MappingType { ref key, .. }) => {
324 self.visit_expression(key_or_index, &Some(*key.clone()))
325 }
326 _ => self.visit_expression(key_or_index, &None),
327 };
328
329 let val_ty = match container_ty {
330 Type::Vector(VectorType { ref element_type }) => {
331 self.visit_expression(val, &Some(*element_type.clone()))
332 }
333 Type::Mapping(MappingType { ref value, .. }) => self.visit_expression(val, &Some(*value.clone())),
334 _ => self.visit_expression(val, &None),
335 };
336
337 vec![(container_ty, container), (key_or_index_ty, key_or_index), (val_ty, val)]
338 }
339
340 Intrinsic::VectorPush => {
341 let [vec, val] = arguments else { panic!("number of arguments is already checked") };
342
343 let vec_ty = self.visit_expression(vec, &None);
345
346 let val_ty = if let Type::Vector(VectorType { element_type }) = &vec_ty {
348 self.visit_expression(val, &Some(*element_type.clone()))
349 } else {
350 self.visit_expression(val, &None)
351 };
352
353 vec![(vec_ty, vec), (val_ty, val)]
354 }
355
356 Intrinsic::VectorSwapRemove => {
357 let [vec, index] = arguments else { panic!("number of arguments is already checked") };
358
359 let vec_ty = self.visit_expression(vec, &None);
360
361 let index_ty = self.visit_expression_infer_default_u32(index);
363
364 vec![(vec_ty, vec), (index_ty, index)]
365 }
366
367 _ => {
369 arguments.iter().map(|arg| (self.visit_expression_reject_numeric(arg, &None), arg)).collect::<Vec<_>>()
370 }
371 };
372
373 let assert_not_mapping_tuple_unit = |type_: &Type, span: Span| {
374 if matches!(type_, Type::Mapping(_) | Type::Tuple(_) | Type::Unit) {
375 self.emit_err(TypeCheckerError::type_should_be2(type_, "anything but a mapping, tuple, or unit", span));
376 }
377 };
378
379 let assert_pedersen_64_bit_input = |type_: &Type, span: Span| {
383 if !matches!(
384 type_,
385 Type::Integer(IntegerType::U8)
386 | Type::Integer(IntegerType::U16)
387 | Type::Integer(IntegerType::U32)
388 | Type::Integer(IntegerType::I8)
389 | Type::Integer(IntegerType::I16)
390 | Type::Integer(IntegerType::I32)
391 | Type::Boolean
392 | Type::Err
393 ) {
394 self.emit_err(TypeCheckerError::type_should_be2(
395 type_,
396 "an integer of less than 64 bits or a bool",
397 span,
398 ));
399 }
400 };
401
402 let assert_pedersen_128_bit_input = |type_: &Type, span: Span| {
409 if !matches!(
410 type_,
411 Type::Integer(IntegerType::U8)
412 | Type::Integer(IntegerType::U16)
413 | Type::Integer(IntegerType::U32)
414 | Type::Integer(IntegerType::U64)
415 | Type::Integer(IntegerType::I8)
416 | Type::Integer(IntegerType::I16)
417 | Type::Integer(IntegerType::I32)
418 | Type::Integer(IntegerType::I64)
419 | Type::Boolean
420 | Type::Err
421 ) {
422 self.emit_err(TypeCheckerError::type_should_be2(
423 type_,
424 "an integer of less than 128 bits or a bool",
425 span,
426 ));
427 }
428 };
429
430 let program_id_regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z0-9_]*\.aleo$").unwrap();
432
433 match intrinsic {
435 Intrinsic::Commit(variant, type_) => {
436 match variant {
437 CommitVariant::CommitPED64 => {
438 assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
439 }
440 CommitVariant::CommitPED128 => {
441 assert_pedersen_128_bit_input(&arguments[0].0, arguments[0].1.span());
442 }
443 _ => {
444 assert_not_mapping_tuple_unit(&arguments[0].0, arguments[0].1.span());
445 }
446 }
447 self.assert_type(&arguments[1].0, &Type::Scalar, arguments[1].1.span());
448 type_.into()
449 }
450 Intrinsic::Hash(variant, type_) => {
451 if variant.requires_byte_alignment() {
453 let input_type = &arguments[0].0;
455 let size_in_bits = match self.state.network {
457 NetworkName::TestnetV0 => input_type
458 .size_in_bits::<TestnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
459 NetworkName::MainnetV0 => input_type
460 .size_in_bits::<MainnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
461 NetworkName::CanaryV0 => input_type
462 .size_in_bits::<CanaryV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
463 };
464 if let Ok(size_in_bits) = size_in_bits {
465 if size_in_bits % 8 != 0 {
467 self.emit_err(TypeCheckerError::type_should_be2(
468 input_type,
469 "a type with a size in bits that is a multiple of 8",
470 arguments[0].1.span(),
471 ));
472 return Type::Err;
473 }
474 };
475 }
476 match variant {
477 HashVariant::HashPED64 => {
478 assert_pedersen_64_bit_input(&arguments[0].0, arguments[0].1.span());
479 }
480 HashVariant::HashPED128 => {
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 type_
488 }
489 Intrinsic::ECDSAVerify(variant) => {
490 let signature_size = ECDSASignature::SIGNATURE_SIZE_IN_BYTES;
492 let Type::Array(array_type) = &arguments[0].0 else {
494 self.emit_err(TypeCheckerError::type_should_be2(
495 &arguments[0].0,
496 format!("a [u8; {signature_size}]"),
497 arguments[0].1.span(),
498 ));
499 return Type::Err;
500 };
501 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[0].1.span());
502 if let Some(length) = array_type.length.as_u32()
503 && length as usize != signature_size
504 {
505 self.emit_err(TypeCheckerError::type_should_be2(
506 &arguments[0].0,
507 format!("a [u8; {signature_size}]"),
508 arguments[0].1.span(),
509 ));
510 return Type::Err;
511 };
512
513 let is_eth = match variant {
515 ECDSAVerifyVariant::Digest => false,
516 ECDSAVerifyVariant::DigestEth => true,
517 ECDSAVerifyVariant::HashKeccak256 => false,
518 ECDSAVerifyVariant::HashKeccak256Raw => false,
519 ECDSAVerifyVariant::HashKeccak256Eth => true,
520 ECDSAVerifyVariant::HashKeccak384 => false,
521 ECDSAVerifyVariant::HashKeccak384Raw => false,
522 ECDSAVerifyVariant::HashKeccak384Eth => true,
523 ECDSAVerifyVariant::HashKeccak512 => false,
524 ECDSAVerifyVariant::HashKeccak512Raw => false,
525 ECDSAVerifyVariant::HashKeccak512Eth => true,
526 ECDSAVerifyVariant::HashSha3_256 => false,
527 ECDSAVerifyVariant::HashSha3_256Raw => false,
528 ECDSAVerifyVariant::HashSha3_256Eth => true,
529 ECDSAVerifyVariant::HashSha3_384 => false,
530 ECDSAVerifyVariant::HashSha3_384Raw => false,
531 ECDSAVerifyVariant::HashSha3_384Eth => true,
532 ECDSAVerifyVariant::HashSha3_512 => false,
533 ECDSAVerifyVariant::HashSha3_512Raw => false,
534 ECDSAVerifyVariant::HashSha3_512Eth => true,
535 };
536 let expected_length = if is_eth {
538 ECDSASignature::ETHEREUM_ADDRESS_SIZE_IN_BYTES
539 } else {
540 ECDSASignature::VERIFYING_KEY_SIZE_IN_BYTES
541 };
542 let Type::Array(array_type) = &arguments[1].0 else {
544 self.emit_err(TypeCheckerError::type_should_be2(
545 &arguments[1].0,
546 format!("a [u8; {expected_length}]"),
547 arguments[1].1.span(),
548 ));
549 return Type::Err;
550 };
551 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[1].1.span());
552 if let Some(length) = array_type.length.as_u32()
553 && length as usize != expected_length
554 {
555 self.emit_err(TypeCheckerError::type_should_be2(
556 &arguments[1].0,
557 format!("a [u8; {expected_length}]"),
558 arguments[1].1.span(),
559 ));
560 return Type::Err;
561 };
562
563 if matches!(&arguments[2].0, Type::Mapping(_) | Type::Tuple(_) | Type::Unit) {
565 self.emit_err(TypeCheckerError::type_should_be2(
566 &arguments[2].0,
567 "anything but a mapping, tuple, or unit",
568 arguments[2].1.span(),
569 ));
570 }
571
572 if matches!(variant, ECDSAVerifyVariant::Digest | ECDSAVerifyVariant::DigestEth) {
574 let expected_length = ECDSASignature::PREHASH_SIZE_IN_BYTES;
576 let Type::Array(array_type) = &arguments[2].0 else {
578 self.emit_err(TypeCheckerError::type_should_be2(
579 &arguments[2].0,
580 format!("a [u8; {expected_length}]"),
581 arguments[2].1.span(),
582 ));
583 return Type::Err;
584 };
585 self.assert_type(array_type.element_type(), &Type::Integer(IntegerType::U8), arguments[2].1.span());
586 if let Some(length) = array_type.length.as_u32()
587 && length as usize != expected_length
588 {
589 self.emit_err(TypeCheckerError::type_should_be2(
590 &arguments[2].0,
591 format!("a [u8; {expected_length}]"),
592 arguments[2].1.span(),
593 ));
594 return Type::Err;
595 }
596 }
597
598 if variant.requires_byte_alignment() {
600 let input_type = &arguments[2].0;
602 let size_in_bits = match self.state.network {
604 NetworkName::TestnetV0 => input_type
605 .size_in_bits::<TestnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
606 NetworkName::MainnetV0 => input_type
607 .size_in_bits::<MainnetV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
608 NetworkName::CanaryV0 => input_type
609 .size_in_bits::<CanaryV0, _>(variant.is_raw(), |_| bail!("structs are not supported")),
610 };
611 if let Ok(size_in_bits) = size_in_bits {
612 if size_in_bits % 8 != 0 {
614 self.emit_err(TypeCheckerError::type_should_be2(
615 input_type,
616 "a type with a size in bits that is a multiple of 8",
617 arguments[2].1.span(),
618 ));
619 return Type::Err;
620 }
621 };
622 }
623
624 Type::Boolean
625 }
626 Intrinsic::Get => {
627 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
628 self.check_access_allowed("Vector::get", true, function_span);
630
631 Type::Optional(OptionalType { inner: Box::new(*element_type.clone()) })
632 } else if let Type::Mapping(MappingType { value, .. }) = &arguments[0].0 {
633 self.check_access_allowed("Mapping::get", true, function_span);
635
636 *value.clone()
637 } else {
638 self.assert_vector_or_mapping_type(&arguments[0].0, arguments[0].1.span());
639 Type::Err
640 }
641 }
642 Intrinsic::Set => {
643 if arguments[0].0.is_vector() {
644 self.check_access_allowed("Vector::set", true, function_span);
646
647 Type::Unit
648 } else if let Type::Mapping(_) = &arguments[0].0 {
649 self.check_access_allowed("Mapping::set", true, function_span);
651
652 Type::Unit
653 } else {
654 self.assert_vector_or_mapping_type(&arguments[0].0, arguments[0].1.span());
655 Type::Err
656 }
657 }
658 Intrinsic::MappingGetOrUse => {
659 self.check_access_allowed("Mapping::get_or_use", true, function_span);
661 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
663
664 let Type::Mapping(mapping_type) = &arguments[0].0 else {
665 return Type::Err;
667 };
668
669 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
671 self.assert_type(&arguments[2].0, &mapping_type.value, arguments[2].1.span());
673
674 mapping_type.value.deref().clone()
675 }
676 Intrinsic::MappingRemove => {
677 self.check_access_allowed("Mapping::remove", true, function_span);
679 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
681
682 let Type::Mapping(mapping_type) = &arguments[0].0 else {
683 return Type::Err;
685 };
686
687 if mapping_type.program != self.scope_state.program_name.unwrap() {
689 self.state
690 .handler
691 .emit_err(TypeCheckerError::cannot_modify_external_mapping("remove", function_span));
692 }
693
694 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
696
697 Type::Unit
698 }
699 Intrinsic::MappingContains => {
700 self.check_access_allowed("Mapping::contains", true, function_span);
702 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
704
705 let Type::Mapping(mapping_type) = &arguments[0].0 else {
706 return Type::Err;
708 };
709
710 self.assert_type(&arguments[1].0, &mapping_type.key, arguments[1].1.span());
712
713 Type::Boolean
714 }
715 Intrinsic::OptionalUnwrap => {
716 self.assert_optional_type(&arguments[0].0, arguments[0].1.span());
718
719 match &arguments[0].0 {
720 Type::Optional(opt) => opt.inner.deref().clone(),
721 _ => Type::Err,
722 }
723 }
724 Intrinsic::OptionalUnwrapOr => {
725 self.assert_optional_type(&arguments[0].0, arguments[0].1.span());
727
728 match &arguments[0].0 {
729 Type::Optional(OptionalType { inner }) => {
730 self.assert_type(&arguments[1].0, inner, arguments[1].1.span());
732 inner.deref().clone()
733 }
734 _ => Type::Err,
735 }
736 }
737 Intrinsic::VectorPush => {
738 self.check_access_allowed("Vector::push", true, function_span);
739
740 match &arguments[0].0 {
742 Type::Vector(VectorType { element_type }) => {
743 self.assert_type(&arguments[1].0, element_type, arguments[1].1.span());
745 Type::Unit
746 }
747 _ => {
748 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
749 Type::Err
750 }
751 }
752 }
753 Intrinsic::VectorLen => {
754 self.check_access_allowed("Vector::len", true, function_span);
755
756 if arguments[0].0.is_vector() {
757 Type::Integer(IntegerType::U32)
758 } else {
759 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
760 Type::Err
761 }
762 }
763 Intrinsic::VectorPop => {
764 self.check_access_allowed("Vector::pop", true, function_span);
765
766 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
767 Type::Optional(OptionalType { inner: Box::new(*element_type.clone()) })
768 } else {
769 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
770 Type::Err
771 }
772 }
773 Intrinsic::VectorSwapRemove => {
774 self.check_access_allowed("Vector::swap_remove", true, function_span);
775
776 if let Type::Vector(VectorType { element_type }) = &arguments[0].0 {
777 *element_type.clone()
778 } else {
779 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
780 Type::Err
781 }
782 }
783 Intrinsic::VectorClear => {
784 if arguments[0].0.is_vector() {
785 Type::Unit
786 } else {
787 self.assert_vector_type(&arguments[0].0, arguments[0].1.span());
788 Type::Err
789 }
790 }
791 Intrinsic::GroupToXCoordinate | Intrinsic::GroupToYCoordinate => {
792 self.assert_type(&arguments[0].0, &Type::Group, arguments[0].1.span());
794 Type::Field
795 }
796 Intrinsic::ChaChaRand(type_) => type_.into(),
797 Intrinsic::SignatureVerify => {
798 assert_not_mapping_tuple_unit(&arguments[2].0, arguments[2].1.span());
801
802 self.assert_type(&arguments[0].0, &Type::Signature, arguments[0].1.span());
804 self.assert_type(&arguments[1].0, &Type::Address, arguments[1].1.span());
806 Type::Boolean
807 }
808 Intrinsic::FutureAwait => Type::Unit,
809 Intrinsic::GroupGen => Type::Group,
810 Intrinsic::ProgramChecksum => {
811 let (type_, expression) = &arguments[0];
813 let span = expression.span();
814 match expression {
816 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
817 if program_id_regex.is_match(s) => {}
818 _ => {
819 self.emit_err(TypeCheckerError::custom(
820 "`Program::checksum` must be called on a program ID, e.g. `foo.aleo`",
821 span,
822 ));
823 }
824 }
825 self.assert_type(type_, &Type::Address, span);
827 Type::Array(ArrayType::new(
829 Type::Integer(IntegerType::U8),
830 Expression::Literal(Literal::integer(
831 IntegerType::U8,
832 "32".to_string(),
833 Default::default(),
834 Default::default(),
835 )),
836 ))
837 }
838 Intrinsic::ProgramEdition => {
839 let (type_, expression) = &arguments[0];
841 let span = expression.span();
842 match expression {
844 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
845 if program_id_regex.is_match(s) => {}
846 _ => {
847 self.emit_err(TypeCheckerError::custom(
848 "`Program::edition` must be called on a program ID, e.g. `foo.aleo`",
849 span,
850 ));
851 }
852 }
853 self.assert_type(type_, &Type::Address, span);
855 Type::Integer(IntegerType::U16)
857 }
858 Intrinsic::ProgramOwner => {
859 let (type_, expression) = &arguments[0];
861 let span = expression.span();
862 match expression {
864 Expression::Literal(Literal { variant: LiteralVariant::Address(s), .. })
865 if program_id_regex.is_match(s) => {}
866 _ => {
867 self.emit_err(TypeCheckerError::custom(
868 "`Program::program_owner` must be called on a program ID, e.g. `foo.aleo`",
869 span,
870 ));
871 }
872 }
873 self.assert_type(type_, &Type::Address, span);
875 Type::Address
877 }
878 Intrinsic::Serialize(variant) => {
879 let is_raw = match variant {
881 SerializeVariant::ToBits => false,
882 SerializeVariant::ToBitsRaw => true,
883 };
884 let input_type = &arguments[0].0;
886
887 let is_allowed_literal_type = |type_: &Type| -> bool {
889 matches!(
890 type_,
891 Type::Boolean
892 | Type::Field
893 | Type::Group
894 | Type::Scalar
895 | Type::Signature
896 | Type::Address
897 | Type::Integer(_)
898 | Type::String
899 | Type::Numeric
900 )
901 };
902
903 let is_allowed = match input_type {
905 Type::Array(array_type) => is_allowed_literal_type(array_type.base_element_type()),
906 type_ => is_allowed_literal_type(type_),
907 };
908 if !is_allowed {
909 self.emit_err(TypeCheckerError::type_should_be2(
910 input_type,
911 "a literal type or an (multi-dimensional) array of literal types",
912 arguments[0].1.span(),
913 ));
914 return Type::Err;
915 }
916
917 let size_in_bits = match self.state.network {
919 NetworkName::TestnetV0 => {
920 input_type.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
921 }
922 NetworkName::MainnetV0 => {
923 input_type.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
924 }
925 NetworkName::CanaryV0 => {
926 input_type.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
927 }
928 };
929
930 if let Ok(size_in_bits) = size_in_bits {
931 let size_in_bits = if size_in_bits > self.limits.max_array_elements {
933 self.emit_err(TypeCheckerError::custom(
934 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),
935 arguments[0].1.span(),
936 ));
937 return Type::Err;
938 } else if size_in_bits == 0 {
939 self.emit_err(TypeCheckerError::custom(
940 "The input type to `Serialize::*` is empty.",
941 arguments[0].1.span(),
942 ));
943 return Type::Err;
944 } else {
945 u32::try_from(size_in_bits).expect("`max_array_elements` should fit in a u32")
946 };
947
948 return Type::Array(ArrayType::bit_array(size_in_bits));
950 }
951
952 Type::Err
954 }
955 Intrinsic::Deserialize(variant, type_) => {
956 let is_raw = match variant {
958 DeserializeVariant::FromBits => false,
959 DeserializeVariant::FromBitsRaw => true,
960 };
961 let input_type = &arguments[0].0;
963
964 let size_in_bits = match self.state.network {
966 NetworkName::TestnetV0 => {
967 type_.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
968 }
969 NetworkName::MainnetV0 => {
970 type_.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
971 }
972 NetworkName::CanaryV0 => {
973 type_.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
974 }
975 };
976
977 if let Ok(size_in_bits) = size_in_bits {
978 let size_in_bits = if size_in_bits > self.limits.max_array_elements {
980 self.emit_err(TypeCheckerError::custom(
981 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),
982 arguments[0].1.span(),
983 ));
984 return Type::Err;
985 } else if size_in_bits == 0 {
986 self.emit_err(TypeCheckerError::custom(
987 "The output type of `Deserialize::*` is empty.",
988 arguments[0].1.span(),
989 ));
990 return Type::Err;
991 } else {
992 u32::try_from(size_in_bits).expect("`max_array_elements` should fit in a u32")
993 };
994
995 let expected_type = Type::Array(ArrayType::bit_array(size_in_bits));
997 if !input_type.eq_flat_relaxed(&expected_type) {
998 self.emit_err(TypeCheckerError::type_should_be2(
999 input_type,
1000 format!("an array of {size_in_bits} bits"),
1001 arguments[0].1.span(),
1002 ));
1003 return Type::Err;
1004 }
1005 };
1006
1007 type_.clone()
1008 }
1009 Intrinsic::CheatCodePrintMapping => {
1010 self.assert_mapping_type(&arguments[0].0, arguments[0].1.span());
1011 Type::Unit
1012 }
1013 Intrinsic::CheatCodeSetBlockHeight => {
1014 self.assert_type(&arguments[0].0, &Type::Integer(IntegerType::U32), arguments[0].1.span());
1015 Type::Unit
1016 }
1017 Intrinsic::CheatCodeSetBlockTimestamp => {
1018 self.assert_type(&arguments[0].0, &Type::Integer(IntegerType::I64), arguments[0].1.span());
1019 Type::Unit
1020 }
1021 Intrinsic::CheatCodeSetSigner => {
1022 self.assert_type(&arguments[0].0, &Type::String, arguments[0].1.span());
1024 if let Expression::Literal(Literal { variant: LiteralVariant::String(s), .. }) = arguments[0].1 {
1026 let s = s.replace("\"", "");
1027 let is_err = match self.state.network {
1028 NetworkName::TestnetV0 => PrivateKey::<TestnetV0>::from_str(&s).is_err(),
1029 NetworkName::MainnetV0 => PrivateKey::<MainnetV0>::from_str(&s).is_err(),
1030 NetworkName::CanaryV0 => PrivateKey::<CanaryV0>::from_str(&s).is_err(),
1031 };
1032 if is_err {
1033 self.emit_err(TypeCheckerError::custom(
1034 "`CheatCode::set_signer` must be called with a valid private key",
1035 arguments[0].1.span(),
1036 ));
1037 }
1038 };
1039 Type::Unit
1040 }
1041 Intrinsic::SelfAddress => Type::Address,
1042 Intrinsic::SelfCaller => {
1043 self.check_access_allowed("self.caller", false, function_span);
1045 Type::Address
1046 }
1047 Intrinsic::SelfChecksum => Type::Array(ArrayType::new(
1048 Type::Integer(IntegerType::U8),
1049 Expression::Literal(Literal::integer(
1050 IntegerType::U8,
1051 "32".to_string(),
1052 Default::default(),
1053 Default::default(),
1054 )),
1055 )),
1056 Intrinsic::SelfEdition => Type::Integer(IntegerType::U16),
1057 Intrinsic::SelfId => Type::Address,
1058 Intrinsic::SelfProgramOwner => {
1059 self.check_access_allowed("program_owner", true, function_span);
1061 Type::Address
1062 }
1063 Intrinsic::SelfSigner => {
1064 self.check_access_allowed("self.signer", false, function_span);
1066 Type::Address
1067 }
1068 Intrinsic::BlockHeight => {
1069 self.check_access_allowed("block.height", true, function_span);
1071 Type::Integer(IntegerType::U32)
1072 }
1073 Intrinsic::BlockTimestamp => {
1074 self.check_access_allowed("block.timestamp", true, function_span);
1076 Type::Integer(IntegerType::I64)
1077 }
1078 Intrinsic::NetworkId => {
1079 self.check_access_allowed("network.id", true, function_span);
1081 Type::Integer(IntegerType::U16)
1082 }
1083 }
1084 }
1085
1086 pub fn assert_member_is_not_record(&mut self, span: Span, parent: Symbol, type_: &Type) {
1088 match type_ {
1089 Type::Composite(struct_)
1090 if self
1091 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1092 .is_some_and(|struct_| struct_.is_record) =>
1093 {
1094 self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(
1095 parent,
1096 struct_.path.clone(),
1097 span,
1098 ))
1099 }
1100 Type::Tuple(tuple_type) => {
1101 for type_ in tuple_type.elements().iter() {
1102 self.assert_member_is_not_record(span, parent, type_)
1103 }
1104 }
1105 _ => {} }
1107 }
1108
1109 pub fn assert_type_is_valid(&mut self, type_: &Type, span: Span) {
1111 match type_ {
1112 Type::Unit => {
1114 self.emit_err(TypeCheckerError::unit_type_only_return(span));
1115 }
1116 Type::String => {
1118 self.emit_err(TypeCheckerError::strings_are_not_supported(span));
1119 }
1120 Type::Composite(struct_)
1122 if self
1123 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1124 .is_none() =>
1125 {
1126 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), span));
1127 }
1128 Type::Tuple(tuple_type) => {
1130 for type_ in tuple_type.elements().iter() {
1131 self.assert_type_is_valid(type_, span);
1132 }
1133 }
1134 Type::Mapping(mapping_type) => {
1136 self.assert_type_is_valid(&mapping_type.key, span);
1137 self.assert_type_is_valid(&mapping_type.value, span);
1138 }
1139 Type::Array(array_type) => {
1141 if let Some(length) = array_type.length.as_u32() {
1144 if length > self.limits.max_array_elements as u32 {
1145 self.emit_err(TypeCheckerError::array_too_large(length, self.limits.max_array_elements, span));
1146 }
1147 } else if let Expression::Literal(_) = &*array_type.length {
1148 self.emit_err(TypeCheckerError::array_too_large_for_u32(span));
1150 }
1151 match array_type.element_type() {
1155 Type::Future(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_future(span)),
1157 Type::Tuple(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span)),
1159 Type::Composite(struct_type) => {
1161 if let Some(struct_) = self.lookup_struct(
1163 struct_type.program.or(self.scope_state.program_name),
1164 &struct_type.path.absolute_path(),
1165 ) {
1166 if struct_.is_record {
1168 self.emit_err(TypeCheckerError::array_element_cannot_be_record(span));
1169 }
1170 }
1171 }
1172 _ => {} }
1174 self.assert_type_is_valid(array_type.element_type(), span);
1175 }
1176
1177 Type::Optional(OptionalType { inner }) => {
1178 if self.disallowed_inside_optional(inner) {
1180 self.emit_err(TypeCheckerError::optional_wrapping_unsupported(inner, span));
1181 }
1182
1183 self.assert_type_is_valid(inner, span);
1185 }
1186
1187 Type::Address
1188 | Type::Boolean
1189 | Type::Composite(_)
1190 | Type::Field
1191 | Type::Future(_)
1192 | Type::Group
1193 | Type::Identifier(_)
1194 | Type::Integer(_)
1195 | Type::Scalar
1196 | Type::Signature
1197 | Type::Vector(_)
1198 | Type::Numeric
1199 | Type::Err => {} }
1201 }
1202
1203 fn disallowed_inside_optional(&mut self, ty: &Type) -> bool {
1205 match ty {
1206 Type::Unit
1207 | Type::Err
1208 | Type::Future(_)
1209 | Type::Identifier(_)
1210 | Type::Mapping(_)
1211 | Type::Optional(_)
1212 | Type::String
1213 | Type::Signature
1214 | Type::Tuple(_)
1215 | Type::Vector(_) => true,
1216
1217 Type::Composite(struct_type) => {
1218 if let Some(struct_) = self.lookup_struct(
1219 struct_type.program.or(self.scope_state.program_name),
1220 &struct_type.path.absolute_path(),
1221 ) {
1222 if struct_.is_record {
1223 return true;
1224 }
1225
1226 for field in &struct_.members {
1228 let field_ty = &field.type_;
1229 let ty_to_check = match field_ty {
1231 Type::Optional(OptionalType { inner }) => inner,
1232 _ => field_ty,
1233 };
1234 if self.disallowed_inside_optional(ty_to_check) {
1235 return true;
1236 }
1237 }
1238 }
1239 false
1240 }
1241
1242 Type::Array(array_type) => {
1243 let elem_type = match array_type.element_type() {
1244 Type::Optional(OptionalType { inner }) => inner,
1245 other => other,
1246 };
1247 self.disallowed_inside_optional(elem_type)
1248 }
1249
1250 Type::Address
1251 | Type::Boolean
1252 | Type::Field
1253 | Type::Group
1254 | Type::Integer(_)
1255 | Type::Numeric
1256 | Type::Scalar => false,
1257 }
1258 }
1259
1260 pub fn assert_storage_type_is_valid(&mut self, type_: &Type, span: Span) {
1263 if type_.is_empty() {
1264 self.emit_err(TypeCheckerError::invalid_storage_type("A zero sized type", span));
1265 }
1266 match type_ {
1267 Type::Unit => {
1269 self.emit_err(TypeCheckerError::invalid_storage_type("unit", span));
1270 }
1271 Type::String => {
1272 self.emit_err(TypeCheckerError::invalid_storage_type("string", span));
1273 }
1274 Type::Signature => {
1275 self.emit_err(TypeCheckerError::invalid_storage_type("signature", span));
1276 }
1277 Type::Future(_) => {
1278 self.emit_err(TypeCheckerError::invalid_storage_type("future", span));
1279 }
1280 Type::Optional(_) => {
1281 self.emit_err(TypeCheckerError::invalid_storage_type("optional", span));
1282 }
1283 Type::Mapping(_) => {
1284 self.emit_err(TypeCheckerError::invalid_storage_type("mapping", span));
1285 }
1286 Type::Tuple(_) => {
1287 self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span));
1288 }
1289
1290 Type::Composite(struct_type) => {
1292 if let Some(struct_) = self.lookup_struct(
1293 struct_type.program.or(self.scope_state.program_name),
1294 &struct_type.path.absolute_path(),
1295 ) {
1296 if struct_.is_record {
1297 self.emit_err(TypeCheckerError::invalid_storage_type("record", span));
1298 return;
1299 }
1300
1301 for field in &struct_.members {
1303 self.assert_storage_type_is_valid(&field.type_, span);
1304 }
1305 } else {
1306 self.emit_err(TypeCheckerError::invalid_storage_type("undefined struct", span));
1307 }
1308 }
1309
1310 Type::Array(array_type) => {
1312 if let Some(length) = array_type.length.as_u32()
1313 && (length == 0 || length > self.limits.max_array_elements as u32)
1314 {
1315 self.emit_err(TypeCheckerError::invalid_storage_type("array", span));
1316 }
1317
1318 let element_ty = array_type.element_type();
1319 match element_ty {
1320 Type::Future(_) => self.emit_err(TypeCheckerError::invalid_storage_type("future", span)),
1321 Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_storage_type("tuple", span)),
1322 Type::Optional(_) => self.emit_err(TypeCheckerError::invalid_storage_type("optional", span)),
1323 _ => {}
1324 }
1325
1326 self.assert_storage_type_is_valid(element_ty, span);
1327 }
1328
1329 Type::Address
1331 | Type::Boolean
1332 | Type::Field
1333 | Type::Group
1334 | Type::Identifier(_)
1335 | Type::Integer(_)
1336 | Type::Scalar
1337 | Type::Numeric
1338 | Type::Err
1339 | Type::Vector(_) => {} }
1341 }
1342
1343 pub fn assert_mapping_type(&self, type_: &Type, span: Span) {
1345 if type_ != &Type::Err && !matches!(type_, Type::Mapping(_)) {
1346 self.emit_err(TypeCheckerError::type_should_be2(type_, "a mapping", span));
1347 }
1348 }
1349
1350 pub fn assert_optional_type(&self, type_: &Type, span: Span) {
1352 if type_ != &Type::Err && !matches!(type_, Type::Optional(_)) {
1353 self.emit_err(TypeCheckerError::type_should_be2(type_, "an optional", span));
1354 }
1355 }
1356
1357 pub fn assert_vector_type(&self, type_: &Type, span: Span) {
1359 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) {
1360 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector", span));
1361 }
1362 }
1363
1364 pub fn assert_vector_or_mapping_type(&self, type_: &Type, span: Span) {
1366 if type_ != &Type::Err && !matches!(type_, Type::Vector(_)) && !matches!(type_, Type::Mapping(_)) {
1367 self.emit_err(TypeCheckerError::type_should_be2(type_, "a vector or a mapping", span));
1368 }
1369 }
1370
1371 pub fn contains_optional_type(&mut self, ty: &Type) -> bool {
1372 let mut visited_paths = IndexSet::<Vec<Symbol>>::new();
1373 self.contains_optional_type_inner(ty, &mut visited_paths)
1374 }
1375
1376 fn contains_optional_type_inner(&mut self, ty: &Type, visited_paths: &mut IndexSet<Vec<Symbol>>) -> bool {
1377 match ty {
1378 Type::Optional(_) => true,
1379
1380 Type::Tuple(tuple) => tuple.elements.iter().any(|e| self.contains_optional_type_inner(e, visited_paths)),
1381
1382 Type::Array(array) => self.contains_optional_type_inner(&array.element_type, visited_paths),
1383
1384 Type::Composite(struct_type) => {
1385 let path = struct_type.path.absolute_path();
1386
1387 if !visited_paths.insert(path.clone()) {
1389 return false;
1390 }
1391
1392 if let Some(comp) = self.lookup_struct(struct_type.program.or(self.scope_state.program_name), &path) {
1393 comp.members
1394 .iter()
1395 .any(|Member { type_, .. }| self.contains_optional_type_inner(type_, visited_paths))
1396 } else {
1397 false
1398 }
1399 }
1400
1401 _ => false,
1402 }
1403 }
1404
1405 pub fn assert_array_type(&self, type_: &Type, span: Span) {
1406 if type_ != &Type::Err && !matches!(type_, Type::Array(_)) {
1407 self.emit_err(TypeCheckerError::type_should_be2(type_, "an array", span));
1408 }
1409 }
1410
1411 pub fn check_function_signature(&mut self, function: &Function, is_stub: bool) {
1413 let function_path = self
1414 .scope_state
1415 .module_name
1416 .iter()
1417 .cloned()
1418 .chain(std::iter::once(function.identifier.name))
1419 .collect::<Vec<Symbol>>();
1420
1421 self.scope_state.variant = Some(function.variant);
1422
1423 let mut inferred_inputs: Vec<Type> = Vec::new();
1424
1425 if self.scope_state.variant == Some(Variant::AsyncFunction) && !self.scope_state.is_stub {
1426 if !function.output.is_empty() {
1428 self.emit_err(TypeCheckerError::async_function_cannot_return_value(function.span()));
1429 }
1430
1431 let mut caller_finalizers = self
1434 .async_function_callers
1435 .get(&Location::new(self.scope_state.program_name.unwrap(), function_path))
1436 .map(|callers| {
1437 callers
1438 .iter()
1439 .flat_map(|caller| {
1440 let caller = Location::new(caller.program, caller.path.clone());
1441 self.state.symbol_table.lookup_function(&caller)
1442 })
1443 .flat_map(|fn_symbol| fn_symbol.finalizer.clone())
1444 })
1445 .into_iter()
1446 .flatten();
1447
1448 if let Some(first) = caller_finalizers.next() {
1449 inferred_inputs = first.inferred_inputs.clone();
1450
1451 for finalizer in caller_finalizers {
1454 assert_eq!(inferred_inputs.len(), finalizer.inferred_inputs.len());
1455 for (t1, t2) in inferred_inputs.iter_mut().zip(finalizer.inferred_inputs.iter()) {
1456 Self::merge_types(t1, t2);
1457 }
1458 }
1459 } else {
1460 self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
1461 function.identifier.name,
1462 function.span(),
1463 ));
1464 }
1465 }
1466
1467 if self.scope_state.variant != Some(Variant::Inline) && !function.const_parameters.is_empty() {
1470 self.emit_err(TypeCheckerError::only_inline_can_have_const_generics(function.identifier.span()));
1471 }
1472
1473 for const_param in &function.const_parameters {
1474 self.visit_type(const_param.type_());
1475
1476 if !matches!(
1478 const_param.type_(),
1479 Type::Boolean | Type::Integer(_) | Type::Address | Type::Scalar | Type::Group | Type::Field
1480 ) {
1481 self.emit_err(TypeCheckerError::bad_const_generic_type(const_param.type_(), const_param.span()));
1482 }
1483
1484 if let Err(err) = self.state.symbol_table.insert_variable(
1486 self.scope_state.program_name.unwrap(),
1487 &[const_param.identifier().name],
1488 VariableSymbol {
1489 type_: const_param.type_().clone(),
1490 span: const_param.identifier.span(),
1491 declaration: VariableType::ConstParameter,
1492 },
1493 ) {
1494 self.state.handler.emit_err(err);
1495 }
1496
1497 self.state.type_table.insert(const_param.identifier().id(), const_param.type_().clone());
1499 }
1500
1501 if function.input.len() > self.limits.max_inputs && function.variant != Variant::Inline {
1503 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_inputs(
1504 function.variant,
1505 function.identifier,
1506 self.limits.max_inputs,
1507 function.input.len(),
1508 function.identifier.span,
1509 ));
1510 }
1511
1512 for (i, input) in function.input.iter().enumerate() {
1514 self.visit_type(input.type_());
1515
1516 let table_type = inferred_inputs.get(i).unwrap_or_else(|| input.type_());
1518
1519 self.assert_type_is_valid(table_type, input.span());
1521
1522 if matches!(table_type, Type::Tuple(_)) {
1524 self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input.span()))
1525 }
1526
1527 if self.contains_optional_type(table_type)
1529 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1530 {
1531 self.emit_err(TypeCheckerError::function_cannot_take_option_as_input(
1532 input.identifier,
1533 table_type,
1534 input.span(),
1535 ))
1536 }
1537
1538 if let Type::Composite(struct_) = table_type {
1540 if !function.variant.is_transition() {
1542 if let Some(elem) = self
1543 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1544 {
1545 if elem.is_record {
1546 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(input.span()))
1547 }
1548 } else {
1549 self.emit_err(TypeCheckerError::undefined_type(struct_.path.clone(), input.span()));
1550 }
1551 }
1552 }
1553
1554 match self.scope_state.variant.unwrap() {
1556 Variant::Transition | Variant::AsyncTransition if input.mode() == Mode::Constant => {
1558 self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input.span()))
1559 }
1560 Variant::Function | Variant::Inline if input.mode() != Mode::None => {
1562 self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input.span()))
1563 }
1564 Variant::AsyncFunction if matches!(input.mode(), Mode::Constant | Mode::Private) => {
1566 self.emit_err(TypeCheckerError::async_function_input_must_be_public(input.span()));
1567 }
1568 _ => {} }
1570
1571 if matches!(table_type, Type::Future(..)) {
1572 if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction)) {
1574 self.emit_err(TypeCheckerError::no_future_parameters(input.span()));
1575 }
1576 }
1577
1578 if !is_stub {
1579 if let Err(err) = self.state.symbol_table.insert_variable(
1581 self.scope_state.program_name.unwrap(),
1582 &[input.identifier().name],
1583 VariableSymbol {
1584 type_: table_type.clone(),
1585 span: input.identifier.span(),
1586 declaration: VariableType::Input(input.mode()),
1587 },
1588 ) {
1589 self.state.handler.emit_err(err);
1590 }
1591
1592 self.state.type_table.insert(input.identifier().id(), table_type.clone());
1594 }
1595 }
1596
1597 if function.output.len() > self.limits.max_outputs && function.variant != Variant::Inline {
1599 self.state.handler.emit_err(TypeCheckerError::function_has_too_many_outputs(
1600 function.variant,
1601 function.identifier,
1602 self.limits.max_outputs,
1603 function.output.len(),
1604 function.identifier.span,
1605 ));
1606 }
1607
1608 function.output.iter().enumerate().for_each(|(index, function_output)| {
1611 self.visit_type(&function_output.type_);
1612
1613 if let Type::Composite(struct_) = function_output.type_.clone()
1616 && let Some(val) =
1617 self.lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
1618 && val.is_record
1619 && !function.variant.is_transition()
1620 {
1621 self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(function_output.span));
1622 }
1623
1624 self.assert_type_is_valid(&function_output.type_, function_output.span);
1626
1627 if matches!(&function_output.type_, Type::Tuple(_)) {
1629 self.emit_err(TypeCheckerError::nested_tuple_type(function_output.span))
1630 }
1631
1632 if self.contains_optional_type(&function_output.type_)
1634 && matches!(function.variant, Variant::Transition | Variant::AsyncTransition | Variant::Function)
1635 {
1636 self.emit_err(TypeCheckerError::function_cannot_return_option_as_output(
1637 &function_output.type_,
1638 function_output.span(),
1639 ))
1640 }
1641
1642 if function_output.mode == Mode::Constant {
1645 self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(function_output.span));
1646 }
1647 if self.scope_state.variant == Some(Variant::AsyncTransition)
1649 && ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
1650 || (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
1651 {
1652 self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
1653 }
1654 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script))
1656 && matches!(function_output.type_, Type::Future(_))
1657 {
1658 self.emit_err(TypeCheckerError::only_async_transition_can_return_future(function_output.span));
1659 }
1660 });
1661
1662 self.visit_type(&function.output_type);
1663 }
1664
1665 fn merge_types(lhs: &mut Type, rhs: &Type) {
1671 if let Type::Future(f1) = lhs {
1672 if let Type::Future(f2) = rhs {
1673 for (i, type_) in f2.inputs.iter().enumerate() {
1674 if let Some(lhs_type) = f1.inputs.get_mut(i) {
1675 Self::merge_types(lhs_type, type_);
1676 } else {
1677 f1.inputs.push(Type::Err);
1678 }
1679 }
1680 } else {
1681 *lhs = Type::Err;
1682 }
1683 } else if !lhs.eq_user(rhs) {
1684 *lhs = Type::Err;
1685 }
1686 }
1687
1688 pub fn lookup_struct(&mut self, program: Option<Symbol>, name: &[Symbol]) -> Option<Composite> {
1690 let record_comp =
1691 program.and_then(|prog| self.state.symbol_table.lookup_record(&Location::new(prog, name.to_vec())));
1692 let comp = record_comp.or_else(|| self.state.symbol_table.lookup_struct(name));
1693 if let Some(s) = comp {
1695 if !s.is_record || program == self.scope_state.program_name {
1697 self.used_structs.insert(name.to_vec());
1698 }
1699 }
1700 comp.cloned()
1701 }
1702
1703 pub fn insert_variable(&mut self, inferred_type: Option<Type>, name: &Identifier, type_: Type, span: Span) {
1705 self.insert_symbol_conditional_scope(name.name);
1706
1707 let is_future = match &type_ {
1708 Type::Future(..) => true,
1709 Type::Tuple(tuple_type) if matches!(tuple_type.elements().last(), Some(Type::Future(..))) => true,
1710 _ => false,
1711 };
1712
1713 if is_future {
1714 if let Some(call_location) = &self.scope_state.call_location {
1717 self.scope_state.futures.insert(name.name, call_location.clone());
1718 }
1719 }
1720
1721 let ty = match (is_future, inferred_type) {
1722 (false, _) => type_,
1723 (true, Some(inferred)) => inferred,
1724 (true, None) => unreachable!("Type checking guarantees the inferred type is present"),
1725 };
1726
1727 if let Err(err) = self.state.symbol_table.insert_variable(
1729 self.scope_state.program_name.unwrap(),
1730 &[name.name],
1731 VariableSymbol { type_: ty.clone(), span, declaration: VariableType::Mut },
1732 ) {
1733 self.state.handler.emit_err(err);
1734 }
1735 }
1736
1737 pub fn check_access_allowed(&mut self, name: &str, finalize_op: bool, span: Span) {
1741 if self.scope_state.variant == Some(Variant::AsyncFunction) && !finalize_op {
1743 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_finalize(name, span));
1744 }
1745 else if self.async_block_id.is_some() && !finalize_op {
1747 self.state.handler.emit_err(TypeCheckerError::invalid_operation_inside_async_block(name, span));
1748 }
1749 else if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
1751 && self.async_block_id.is_none()
1752 && finalize_op
1753 {
1754 self.state.handler.emit_err(TypeCheckerError::invalid_operation_outside_finalize(name, span));
1755 }
1756 }
1757
1758 pub fn is_external_record(&self, ty: &Type) -> bool {
1759 if let Type::Composite(typ) = &ty {
1760 let this_program = self.scope_state.program_name.unwrap();
1761 let program = typ.program.unwrap_or(this_program);
1762 program != this_program
1763 && self
1764 .state
1765 .symbol_table
1766 .lookup_record(&Location::new(program, typ.path.absolute_path().to_vec()))
1767 .is_some()
1768 } else {
1769 false
1770 }
1771 }
1772
1773 pub fn parse_integer_literal<I: FromStrRadix>(&self, raw_string: &str, span: Span, type_string: &str) {
1774 let string = raw_string.replace('_', "");
1775 if I::from_str_by_radix(&string).is_err() {
1776 self.state.handler.emit_err(TypeCheckerError::invalid_int_value(string, type_string, span));
1777 }
1778 }
1779
1780 pub fn emit_inference_failure_error(&self, ty: &mut Type, expr: &Expression) {
1783 self.emit_err(TypeCheckerError::could_not_determine_type(expr.clone(), expr.span()));
1784 *ty = Type::Err;
1785 self.state.type_table.insert(expr.id(), Type::Err);
1786 }
1787
1788 pub fn check_numeric_literal(&self, input: &Literal, ty: &Type) -> bool {
1791 if let Literal { variant: LiteralVariant::Unsuffixed(s), .. } = input {
1792 let span = input.span();
1793 let has_nondecimal_prefix =
1794 |s: &str| ["0x", "0o", "0b", "-0x", "-0o", "-0b"].iter().any(|p| s.starts_with(p));
1795
1796 macro_rules! parse_int {
1797 ($t:ty, $name:expr) => {
1798 self.parse_integer_literal::<$t>(s, span, $name)
1799 };
1800 }
1801
1802 match ty {
1803 Type::Integer(kind) => match kind {
1804 IntegerType::U8 => parse_int!(u8, "u8"),
1805 IntegerType::U16 => parse_int!(u16, "u16"),
1806 IntegerType::U32 => parse_int!(u32, "u32"),
1807 IntegerType::U64 => parse_int!(u64, "u64"),
1808 IntegerType::U128 => parse_int!(u128, "u128"),
1809 IntegerType::I8 => parse_int!(i8, "i8"),
1810 IntegerType::I16 => parse_int!(i16, "i16"),
1811 IntegerType::I32 => parse_int!(i32, "i32"),
1812 IntegerType::I64 => parse_int!(i64, "i64"),
1813 IntegerType::I128 => parse_int!(i128, "i128"),
1814 },
1815 Type::Group => {
1816 if has_nondecimal_prefix(s) {
1817 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1819 return false;
1820 } else {
1821 let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1822 if !trimmed.is_empty()
1823 && format!("{trimmed}group")
1824 .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1825 .is_err()
1826 {
1827 self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1828 return false;
1829 }
1830 }
1831 }
1832 Type::Field | Type::Scalar => {
1833 if has_nondecimal_prefix(s) {
1834 self.emit_err(TypeCheckerError::hexbin_literal_nonintegers(span));
1836 return false;
1837 }
1838 }
1839 _ => {
1840 }
1842 }
1843 }
1844 true
1845 }
1846}