1use super::*;
18use crate::{VariableSymbol, VariableType};
19
20use leo_ast::{
21 Type::{Future, Tuple},
22 *,
23};
24use leo_errors::{TypeCheckerError, TypeCheckerWarning};
25use leo_span::{Span, Symbol, sym};
26
27use itertools::Itertools as _;
28
29impl TypeCheckingVisitor<'_> {
30 pub fn visit_expression_assign(&mut self, input: &Expression) -> (Type, bool) {
33 let (ty, is_storage) = match input {
34 Expression::ArrayAccess(array_access) => {
35 (self.visit_array_access_general(array_access, true, &None), false)
36 }
37 Expression::Path(path) if path.qualifier().is_empty() => self.visit_path_assign(path),
38 Expression::MemberAccess(member_access) => {
39 (self.visit_member_access_general(member_access, true, &None), false)
40 }
41 Expression::TupleAccess(tuple_access) => {
42 (self.visit_tuple_access_general(tuple_access, true, &None), false)
43 }
44 _ => {
45 self.emit_err(TypeCheckerError::invalid_assignment_target(input, input.span()));
46 (Type::Err, false)
47 }
48 };
49
50 let external_record = self.is_external_record(&ty);
52 let external_record_tuple =
53 matches!(&ty, Type::Tuple(tuple) if tuple.elements().iter().any(|ty| self.is_external_record(ty)));
54
55 if external_record || external_record_tuple {
56 let Expression::Path(path) = input else {
57 return (Type::Err, false);
59 };
60
61 if !self.symbol_in_conditional_scope(path.identifier().name) {
62 if external_record {
63 self.emit_err(TypeCheckerError::assignment_to_external_record_cond(&ty, input.span()));
64 } else {
65 self.emit_err(TypeCheckerError::assignment_to_external_record_tuple_cond(&ty, input.span()));
67 }
68 }
69 }
70
71 if let Type::Future(..) = ty {
73 self.emit_err(TypeCheckerError::cannot_reassign_future_variable(input, input.span()));
74 }
75
76 if let Type::Mapping(_) = ty {
78 self.emit_err(TypeCheckerError::cannot_reassign_mapping(input, input.span()));
79 }
80
81 self.state.type_table.insert(input.id(), ty.clone());
83
84 (ty, is_storage)
85 }
86
87 pub fn visit_array_access_general(&mut self, input: &ArrayAccess, assign: bool, expected: &Option<Type>) -> Type {
88 let this_type = if assign {
90 self.visit_expression_assign(&input.array).0
91 } else {
92 self.visit_expression(&input.array, &None)
93 };
94 self.assert_array_type(&this_type, input.array.span());
95
96 let mut index_type = self.visit_expression(&input.index, &None);
98
99 if index_type == Type::Numeric {
100 index_type = Type::Integer(IntegerType::U32);
103 if let Expression::Literal(literal) = &input.index {
104 self.check_numeric_literal(literal, &index_type);
105 }
106 }
107
108 self.assert_int_type(&index_type, input.index.span());
109
110 self.state.type_table.insert(input.index.id(), index_type.clone());
113
114 let Type::Array(array_type) = this_type else {
116 return Type::Err;
118 };
119
120 let element_type = array_type.element_type();
121
122 self.maybe_assert_type(element_type, expected, input.span());
124
125 element_type.clone()
127 }
128
129 pub fn visit_member_access_general(&mut self, input: &MemberAccess, assign: bool, expected: &Option<Type>) -> Type {
130 let ty = if assign {
131 self.visit_expression_assign(&input.inner).0
132 } else {
133 self.visit_expression(&input.inner, &None)
134 };
135
136 if assign && self.is_external_record(&ty) {
138 self.emit_err(TypeCheckerError::assignment_to_external_record_member(&ty, input.span));
139 }
140
141 match ty {
143 Type::Err => Type::Err,
144 Type::Composite(ref struct_) => {
145 let Some(struct_) = self
147 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
148 else {
149 self.emit_err(TypeCheckerError::undefined_type(ty, input.inner.span()));
150 return Type::Err;
151 };
152 match struct_.members.iter().find(|member| member.name() == input.name.name) {
154 Some(Member { type_, .. }) => {
156 self.maybe_assert_type(type_, expected, input.span());
158 type_.clone()
159 }
160 None => {
162 self.emit_err(TypeCheckerError::invalid_struct_variable(
163 input.name,
164 &struct_,
165 input.name.span(),
166 ));
167 Type::Err
168 }
169 }
170 }
171 type_ => {
172 self.emit_err(TypeCheckerError::type_should_be2(type_, "a struct or record", input.inner.span()));
173 Type::Err
174 }
175 }
176 }
177
178 pub fn visit_tuple_access_general(&mut self, input: &TupleAccess, assign: bool, expected: &Option<Type>) -> Type {
179 let this_type = if assign {
180 self.visit_expression_assign(&input.tuple).0
181 } else {
182 self.visit_expression(&input.tuple, &None)
183 };
184 match this_type {
185 Type::Err => Type::Err,
186 Type::Tuple(tuple) => {
187 let index = input.index.value();
189 let Some(actual) = tuple.elements().get(index) else {
190 self.emit_err(TypeCheckerError::tuple_out_of_range(index, tuple.length(), input.span()));
191 return Type::Err;
192 };
193
194 self.maybe_assert_type(actual, expected, input.span());
195
196 actual.clone()
197 }
198 Type::Future(_) => {
199 let Some(Type::Future(inferred_f)) = self.state.type_table.get(&input.tuple.id()) else {
201 return Type::Err;
203 };
204
205 if inferred_f.location.is_none() {
206 self.emit_err(TypeCheckerError::invalid_async_block_future_access(input.span()));
209 return Type::Err;
210 }
211
212 let Some(actual) = inferred_f.inputs().get(input.index.value()) else {
213 self.emit_err(TypeCheckerError::invalid_future_access(
214 input.index.value(),
215 inferred_f.inputs().len(),
216 input.span(),
217 ));
218 return Type::Err;
219 };
220
221 if let Type::Err = actual {
223 self.emit_err(TypeCheckerError::future_error_member(input.index.value(), input.span()));
224 return Type::Err;
225 }
226
227 self.maybe_assert_type(actual, expected, input.span());
228
229 actual.clone()
230 }
231 type_ => {
232 self.emit_err(TypeCheckerError::type_should_be2(type_, "a tuple or future", input.span()));
233 Type::Err
234 }
235 }
236 }
237
238 pub fn visit_path_assign(&mut self, input: &Path) -> (Type, bool) {
241 let Some(var) =
243 self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path())
244 else {
245 self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span));
246 return (Type::Err, false);
247 };
248
249 if var.type_.is_vector() {
251 self.emit_err(TypeCheckerError::invalid_assignment_target(input, input.span()));
252 return (Type::Err, false);
253 }
254
255 match &var.declaration {
257 VariableType::Const => self.emit_err(TypeCheckerError::cannot_assign_to_const_var(input, var.span)),
258 VariableType::ConstParameter => {
259 self.emit_err(TypeCheckerError::cannot_assign_to_generic_const_function_parameter(input, input.span))
260 }
261 VariableType::Input(Mode::Constant) => {
262 self.emit_err(TypeCheckerError::cannot_assign_to_const_input(input, var.span))
263 }
264 VariableType::Storage => return (var.type_.clone(), true),
265 VariableType::Mut | VariableType::Input(_) => {}
266 }
267
268 if self.scope_state.variant.unwrap().is_async_function()
270 && !self.symbol_in_conditional_scope(input.identifier().name)
271 {
272 self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "function", var.span));
273 }
274
275 if self.async_block_id.is_some() && !self.symbol_in_conditional_scope(input.identifier().name) {
277 self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "block", var.span));
278 }
279
280 if let Some(async_block_id) = self.async_block_id
281 && !self.state.symbol_table.is_defined_in_scope_or_ancestor_until(async_block_id, input.identifier().name)
282 {
283 self.emit_err(TypeCheckerError::cannot_assign_to_vars_outside_async_block(
287 input.identifier().name,
288 input.span,
289 ));
290 }
291
292 (var.type_.clone(), false)
293 }
294
295 pub(crate) fn visit_expression_reject_numeric(&mut self, expr: &Expression, expected: &Option<Type>) -> Type {
298 let mut inferred = self.visit_expression(expr, expected);
299 match inferred {
300 Type::Numeric => {
301 self.emit_inference_failure_error(&mut inferred, expr);
302 Type::Err
303 }
304 _ => inferred,
305 }
306 }
307
308 pub(crate) fn visit_expression_infer_default_u32(&mut self, expr: &Expression) -> Type {
311 let mut inferred = self.visit_expression(expr, &None);
312
313 if inferred == Type::Numeric {
314 inferred = Type::Integer(IntegerType::U32);
315
316 if let Expression::Literal(literal) = expr
317 && !self.check_numeric_literal(literal, &inferred)
318 {
319 inferred = Type::Err;
320 }
321
322 self.state.type_table.insert(expr.id(), inferred.clone());
323 }
324
325 inferred
326 }
327}
328
329impl AstVisitor for TypeCheckingVisitor<'_> {
330 type AdditionalInput = Option<Type>;
331 type Output = Type;
332
333 fn visit_array_type(&mut self, input: &ArrayType) {
335 self.visit_type(&input.element_type);
336 self.visit_expression_infer_default_u32(&input.length);
337 }
338
339 fn visit_composite_type(&mut self, input: &CompositeType) {
340 let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
341
342 if let Some(struct_) = struct_ {
343 if struct_.const_parameters.len() != input.const_arguments.len() {
345 self.emit_err(TypeCheckerError::incorrect_num_const_args(
346 "Struct type",
347 struct_.const_parameters.len(),
348 input.const_arguments.len(),
349 input.path.span,
350 ));
351 }
352
353 for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
355 self.visit_expression(argument, &Some(expected.type_().clone()));
356 }
357 } else if !input.const_arguments.is_empty() {
358 self.emit_err(TypeCheckerError::unexpected_const_args(input, input.path.span));
359 }
360 }
361
362 fn visit_expression(&mut self, input: &Expression, additional: &Self::AdditionalInput) -> Self::Output {
364 let output = match input {
365 Expression::Array(array) => self.visit_array(array, additional),
366 Expression::ArrayAccess(access) => self.visit_array_access_general(access, false, additional),
367 Expression::Intrinsic(intr) => self.visit_intrinsic(intr, additional),
368 Expression::Async(async_) => self.visit_async(async_, additional),
369 Expression::Binary(binary) => self.visit_binary(binary, additional),
370 Expression::Call(call) => self.visit_call(call, additional),
371 Expression::Cast(cast) => self.visit_cast(cast, additional),
372 Expression::Struct(struct_) => self.visit_struct_init(struct_, additional),
373 Expression::Err(err) => self.visit_err(err, additional),
374 Expression::Path(path) => self.visit_path(path, additional),
375 Expression::Literal(literal) => self.visit_literal(literal, additional),
376 Expression::Locator(locator) => self.visit_locator(locator, additional),
377 Expression::MemberAccess(access) => self.visit_member_access_general(access, false, additional),
378 Expression::Repeat(repeat) => self.visit_repeat(repeat, additional),
379 Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
380 Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
381 Expression::TupleAccess(access) => self.visit_tuple_access_general(access, false, additional),
382 Expression::Unary(unary) => self.visit_unary(unary, additional),
383 Expression::Unit(unit) => self.visit_unit(unit, additional),
384 };
385
386 self.state.type_table.insert(input.id(), output.clone());
388 output
389 }
390
391 fn visit_array_access(&mut self, _input: &ArrayAccess, _additional: &Self::AdditionalInput) -> Self::Output {
392 panic!("Should not be called.");
393 }
394
395 fn visit_member_access(&mut self, _input: &MemberAccess, _additional: &Self::AdditionalInput) -> Self::Output {
396 panic!("Should not be called.");
397 }
398
399 fn visit_tuple_access(&mut self, _input: &TupleAccess, _additional: &Self::AdditionalInput) -> Self::Output {
400 panic!("Should not be called.");
401 }
402
403 fn visit_array(&mut self, input: &ArrayExpression, additional: &Self::AdditionalInput) -> Self::Output {
404 let element_type = match additional {
407 Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
408 Some(Type::Optional(opt)) => match &*opt.inner {
409 Type::Array(array_ty) => Some(array_ty.element_type().clone()),
410 _ => None,
411 },
412 _ => None,
413 };
414
415 let inferred_type = if input.elements.is_empty() {
416 if let Some(ty) = element_type.clone() {
417 ty
418 } else {
419 self.emit_err(TypeCheckerError::could_not_determine_type(input, input.span()));
420 Type::Err
421 }
422 } else {
423 self.visit_expression_reject_numeric(&input.elements[0], &element_type)
424 };
425
426 if input.elements.len() > self.limits.max_array_elements {
427 self.emit_err(TypeCheckerError::array_too_large(
428 input.elements.len(),
429 self.limits.max_array_elements,
430 input.span(),
431 ));
432 }
433
434 for expression in input.elements.iter().skip(1) {
435 let next_type = self.visit_expression_reject_numeric(expression, &element_type);
436
437 if next_type == Type::Err {
438 return Type::Err;
439 }
440
441 if let Some(ref element_type) = element_type {
442 self.assert_type(&next_type, element_type, expression.span());
443 } else {
444 self.assert_type(&next_type, &inferred_type, expression.span());
445 }
446 }
447
448 if inferred_type == Type::Err {
449 return Type::Err;
450 }
451
452 let type_ = Type::Array(ArrayType::new(
453 inferred_type,
454 Expression::Literal(Literal {
455 variant: LiteralVariant::Integer(IntegerType::U32, input.elements.len().to_string()),
457 id: self.state.node_builder.next_id(),
458 span: Span::default(),
459 }),
460 ));
461
462 self.maybe_assert_type(&type_, additional, input.span());
463
464 type_
465 }
466
467 fn visit_repeat(&mut self, input: &RepeatExpression, additional: &Self::AdditionalInput) -> Self::Output {
468 let expected_element_type = match additional {
471 Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
472 Some(Type::Optional(opt)) => match &*opt.inner {
473 Type::Array(array_ty) => Some(array_ty.element_type().clone()),
474 _ => None,
475 },
476 _ => None,
477 };
478
479 let inferred_element_type = self.visit_expression_reject_numeric(&input.expr, &expected_element_type);
480
481 self.visit_expression_infer_default_u32(&input.count);
484
485 if let Some(count) = input.count.as_u32()
488 && count > self.limits.max_array_elements as u32
489 {
490 self.emit_err(TypeCheckerError::array_too_large(count, self.limits.max_array_elements, input.span()));
491 }
492
493 let type_ = Type::Array(ArrayType::new(inferred_element_type, input.count.clone()));
494
495 self.maybe_assert_type(&type_, additional, input.span());
496 type_
497 }
498
499 fn visit_intrinsic(&mut self, input: &IntrinsicExpression, expected: &Self::AdditionalInput) -> Self::Output {
500 let Some(core_instruction) = self.get_intrinsic(input) else {
502 self.emit_err(TypeCheckerError::invalid_core_function_call(input, input.span()));
503 return Type::Err;
504 };
505 if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
507 && self.async_block_id.is_none()
508 && core_instruction.is_finalize_command()
509 {
510 self.emit_err(TypeCheckerError::operation_must_be_in_async_block_or_function(input.span()));
511 }
512
513 let return_type = self.check_intrinsic(core_instruction.clone(), &input.arguments, expected, input.span());
514
515 self.maybe_assert_type(&return_type, expected, input.span());
517
518 if core_instruction == Intrinsic::FutureAwait && input.arguments.len() != 1 {
520 self.emit_err(TypeCheckerError::can_only_await_one_future_at_a_time(input.span));
521 }
522
523 return_type
524 }
525
526 fn visit_async(&mut self, input: &AsyncExpression, _additional: &Self::AdditionalInput) -> Self::Output {
527 self.async_block_id = Some(input.block.id);
529
530 if self.scope_state.is_conditional {
532 self.emit_err(TypeCheckerError::async_block_in_conditional(input.span));
533 }
534
535 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
536 self.emit_err(TypeCheckerError::illegal_async_block_location(input.span));
537 }
538
539 if self.scope_state.already_contains_an_async_block {
540 self.emit_err(TypeCheckerError::multiple_async_blocks_not_allowed(input.span));
541 }
542
543 if self.scope_state.has_called_finalize {
544 self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
545 }
546
547 self.visit_block(&input.block);
548
549 self.scope_state.already_contains_an_async_block = true;
551
552 self.async_block_id = None;
554
555 Type::Future(FutureType::new(Vec::new(), None, false))
558 }
559
560 fn visit_binary(&mut self, input: &BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
561 let assert_same_type = |slf: &Self, t1: &Type, t2: &Type| -> Type {
562 if t1 == &Type::Err || t2 == &Type::Err {
563 Type::Err
564 } else if !t1.eq_user(t2) {
565 slf.emit_err(TypeCheckerError::operation_types_mismatch(input.op, t1, t2, input.span()));
566 Type::Err
567 } else {
568 t1.clone()
569 }
570 };
571
572 let infer_numeric_types = |slf: &Self, left_type: &mut Type, right_type: &mut Type| {
580 use Type::*;
581
582 match (&*left_type, &*right_type) {
583 (Numeric, Numeric) => {
585 slf.emit_inference_failure_error(left_type, &input.left);
586 slf.emit_inference_failure_error(right_type, &input.right);
587 }
588
589 (Numeric, Err) => slf.emit_inference_failure_error(left_type, &input.left),
591
592 (Err, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
594
595 (Integer(_) | Field | Group | Scalar, Numeric) => {
597 *right_type = left_type.clone();
598 slf.state.type_table.insert(input.right.id(), right_type.clone());
599 if let Expression::Literal(literal) = &input.right {
600 slf.check_numeric_literal(literal, right_type);
601 }
602 }
603
604 (Numeric, Integer(_) | Field | Group | Scalar) => {
606 *left_type = right_type.clone();
607 slf.state.type_table.insert(input.left.id(), left_type.clone());
608 if let Expression::Literal(literal) = &input.left {
609 slf.check_numeric_literal(literal, left_type);
610 }
611 }
612
613 (Numeric, _) => slf.emit_inference_failure_error(left_type, &input.left),
615
616 (_, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
618
619 _ => {}
621 }
622 };
623
624 match input.op {
625 BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
626 self.maybe_assert_type(&Type::Boolean, destination, input.span());
627 self.visit_expression(&input.left, &Some(Type::Boolean));
628 self.visit_expression(&input.right, &Some(Type::Boolean));
629 Type::Boolean
630 }
631 BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
632 let operand_expected = self.unwrap_optional_type(destination);
633
634 let mut t1 = self.visit_expression(&input.left, &operand_expected);
636 let mut t2 = self.visit_expression(&input.right, &operand_expected);
637
638 infer_numeric_types(self, &mut t1, &mut t2);
640
641 self.assert_bool_int_type(&t1, input.left.span());
643 self.assert_bool_int_type(&t2, input.right.span());
644
645 let result_t = assert_same_type(self, &t1, &t2);
646 self.maybe_assert_type(&result_t, destination, input.span());
647
648 result_t
649 }
650 BinaryOperation::Add => {
651 let operand_expected = self.unwrap_optional_type(destination);
652
653 let mut t1 = self.visit_expression(&input.left, &operand_expected);
655 let mut t2 = self.visit_expression(&input.right, &operand_expected);
656
657 infer_numeric_types(self, &mut t1, &mut t2);
659
660 let assert_add_type = |type_: &Type, span: Span| {
662 if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Scalar | Type::Integer(_)) {
663 self.emit_err(TypeCheckerError::type_should_be2(
664 type_,
665 "a field, group, scalar, or integer",
666 span,
667 ));
668 }
669 };
670
671 assert_add_type(&t1, input.left.span());
672 assert_add_type(&t2, input.right.span());
673
674 let result_t = assert_same_type(self, &t1, &t2);
675
676 self.maybe_assert_type(&result_t, destination, input.span());
677
678 result_t
679 }
680 BinaryOperation::Sub => {
681 let operand_expected = self.unwrap_optional_type(destination);
682
683 let mut t1 = self.visit_expression(&input.left, &operand_expected);
685 let mut t2 = self.visit_expression(&input.right, &operand_expected);
686
687 infer_numeric_types(self, &mut t1, &mut t2);
689
690 self.assert_field_group_int_type(&t1, input.left.span());
692 self.assert_field_group_int_type(&t2, input.right.span());
693
694 let result_t = assert_same_type(self, &t1, &t2);
695
696 self.maybe_assert_type(&result_t, destination, input.span());
697
698 result_t
699 }
700 BinaryOperation::Mul => {
701 let unwrapped_dest = self.unwrap_optional_type(destination);
702
703 let expected = if matches!(unwrapped_dest, Some(Type::Group)) { &None } else { &unwrapped_dest };
707 let mut t1 = self.visit_expression(&input.left, expected);
708 let mut t2 = self.visit_expression(&input.right, expected);
709
710 match (&t1, &t2) {
716 (Type::Group, Type::Numeric) => infer_numeric_types(self, &mut Type::Scalar, &mut t2),
717 (Type::Numeric, Type::Group) => infer_numeric_types(self, &mut t1, &mut Type::Scalar),
718 (Type::Scalar, Type::Numeric) => infer_numeric_types(self, &mut Type::Group, &mut t2),
719 (Type::Numeric, Type::Scalar) => infer_numeric_types(self, &mut t1, &mut Type::Group),
720 (_, _) => infer_numeric_types(self, &mut t1, &mut t2),
721 }
722
723 let result_t = match (&t1, &t2) {
725 (Type::Err, _) | (_, Type::Err) => Type::Err,
726 (Type::Group, Type::Scalar) | (Type::Scalar, Type::Group) => Type::Group,
727 (Type::Field, Type::Field) => Type::Field,
728 (Type::Integer(integer_type1), Type::Integer(integer_type2)) if integer_type1 == integer_type2 => {
729 t1.clone()
730 }
731 _ => {
732 self.emit_err(TypeCheckerError::mul_types_mismatch(t1, t2, input.span()));
733 Type::Err
734 }
735 };
736
737 self.maybe_assert_type(&result_t, destination, input.span());
738
739 result_t
740 }
741 BinaryOperation::Div => {
742 let operand_expected = self.unwrap_optional_type(destination);
743
744 let mut t1 = self.visit_expression(&input.left, &operand_expected);
746 let mut t2 = self.visit_expression(&input.right, &operand_expected);
747
748 infer_numeric_types(self, &mut t1, &mut t2);
750
751 self.assert_field_int_type(&t1, input.left.span());
753 self.assert_field_int_type(&t2, input.right.span());
754
755 let result_t = assert_same_type(self, &t1, &t2);
756
757 self.maybe_assert_type(&result_t, destination, input.span());
758
759 result_t
760 }
761 BinaryOperation::Rem | BinaryOperation::RemWrapped => {
762 let operand_expected = self.unwrap_optional_type(destination);
763
764 let mut t1 = self.visit_expression(&input.left, &operand_expected);
766 let mut t2 = self.visit_expression(&input.right, &operand_expected);
767
768 infer_numeric_types(self, &mut t1, &mut t2);
770
771 self.assert_int_type(&t1, input.left.span());
773 self.assert_int_type(&t2, input.right.span());
774
775 let result_t = assert_same_type(self, &t1, &t2);
776
777 self.maybe_assert_type(&result_t, destination, input.span());
778
779 result_t
780 }
781 BinaryOperation::Mod => {
782 let operand_expected = self.unwrap_optional_type(destination);
783
784 let mut t1 = self.visit_expression(&input.left, &operand_expected);
786 let mut t2 = self.visit_expression(&input.right, &operand_expected);
787
788 infer_numeric_types(self, &mut t1, &mut t2);
790
791 self.assert_unsigned_type(&t1, input.left.span());
793 self.assert_unsigned_type(&t2, input.right.span());
794
795 let result_t = assert_same_type(self, &t1, &t2);
796
797 self.maybe_assert_type(&result_t, destination, input.span());
798
799 result_t
800 }
801 BinaryOperation::Pow => {
802 let operand_expected = self.unwrap_optional_type(destination);
803
804 let mut t1 = self.visit_expression(&input.left, &operand_expected);
806
807 let mut t2 = self.visit_expression(&input.right, &None);
809
810 if matches!((&t1, &t2), (Type::Field, Type::Numeric) | (Type::Numeric, Type::Field)) {
813 infer_numeric_types(self, &mut t1, &mut t2);
814 } else {
815 if matches!(t1, Type::Numeric) {
816 self.emit_inference_failure_error(&mut t1, &input.left);
817 }
818 if matches!(t2, Type::Numeric) {
819 self.emit_inference_failure_error(&mut t2, &input.right);
820 }
821 }
822
823 let ty = match (&t1, &t2) {
825 (Type::Err, _) | (_, Type::Err) => Type::Err,
826 (Type::Field, Type::Field) => Type::Field,
827 (base @ Type::Integer(_), t2) => {
828 if !matches!(
829 t2,
830 Type::Integer(IntegerType::U8)
831 | Type::Integer(IntegerType::U16)
832 | Type::Integer(IntegerType::U32)
833 ) {
834 self.emit_err(TypeCheckerError::pow_types_mismatch(base, t2, input.span()));
835 }
836 base.clone()
837 }
838 _ => {
839 self.emit_err(TypeCheckerError::pow_types_mismatch(t1, t2, input.span()));
840 Type::Err
841 }
842 };
843
844 self.maybe_assert_type(&ty, destination, input.span());
845
846 ty
847 }
848 BinaryOperation::Eq | BinaryOperation::Neq => {
849 let (mut t1, mut t2) =
859 if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.right {
860 let t1 = self.visit_expression(&input.left, &None);
861 (t1.clone(), self.visit_expression(&input.right, &Some(t1.clone())))
862 } else if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.left {
863 let t2 = self.visit_expression(&input.right, &None);
864 (self.visit_expression(&input.left, &Some(t2.clone())), t2)
865 } else {
866 (self.visit_expression(&input.left, &None), self.visit_expression(&input.right, &None))
867 };
868
869 infer_numeric_types(self, &mut t1, &mut t2);
871
872 let _ = assert_same_type(self, &t1, &t2);
874
875 self.maybe_assert_type(&Type::Boolean, destination, input.span());
876
877 Type::Boolean
878 }
879 BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Lte | BinaryOperation::Gte => {
880 let mut t1 = self.visit_expression(&input.left, &None);
882 let mut t2 = self.visit_expression(&input.right, &None);
883
884 infer_numeric_types(self, &mut t1, &mut t2);
886
887 let assert_compare_type = |type_: &Type, span: Span| {
889 if !matches!(type_, Type::Err | Type::Field | Type::Scalar | Type::Integer(_)) {
890 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, scalar, or integer", span));
891 }
892 };
893
894 assert_compare_type(&t1, input.left.span());
895 assert_compare_type(&t2, input.right.span());
896
897 let _ = assert_same_type(self, &t1, &t2);
898
899 self.maybe_assert_type(&Type::Boolean, destination, input.span());
900
901 Type::Boolean
902 }
903 BinaryOperation::AddWrapped
904 | BinaryOperation::SubWrapped
905 | BinaryOperation::DivWrapped
906 | BinaryOperation::MulWrapped => {
907 let operand_expected = self.unwrap_optional_type(destination);
908
909 let mut t1 = self.visit_expression(&input.left, &operand_expected);
911 let mut t2 = self.visit_expression(&input.right, &operand_expected);
912
913 infer_numeric_types(self, &mut t1, &mut t2);
915
916 self.assert_int_type(&t1, input.left.span());
918 self.assert_int_type(&t2, input.right.span());
919
920 let result_t = assert_same_type(self, &t1, &t2);
921
922 self.maybe_assert_type(&result_t, destination, input.span());
923
924 result_t
925 }
926 BinaryOperation::Shl
927 | BinaryOperation::ShlWrapped
928 | BinaryOperation::Shr
929 | BinaryOperation::ShrWrapped
930 | BinaryOperation::PowWrapped => {
931 let operand_expected = self.unwrap_optional_type(destination);
932
933 let t1 = self.visit_expression_reject_numeric(&input.left, &operand_expected);
935
936 let t2 = self.visit_expression_reject_numeric(&input.right, &None);
938
939 self.assert_int_type(&t1, input.left.span());
940
941 if !matches!(
942 &t2,
943 Type::Err
944 | Type::Integer(IntegerType::U8)
945 | Type::Integer(IntegerType::U16)
946 | Type::Integer(IntegerType::U32)
947 ) {
948 self.emit_err(TypeCheckerError::shift_type_magnitude(input.op, t2, input.right.span()));
949 }
950
951 t1
952 }
953 }
954 }
955
956 fn visit_call(&mut self, input: &CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
957 let callee_program = input.program.or(self.scope_state.program_name).unwrap();
958
959 let callee_path = input.function.absolute_path();
960
961 let Some(func_symbol) =
962 self.state.symbol_table.lookup_function(&Location::new(callee_program, callee_path.clone()))
963 else {
964 self.emit_err(TypeCheckerError::unknown_sym("function", input.function.clone(), input.function.span()));
965 return Type::Err;
966 };
967
968 let func = func_symbol.function.clone();
969
970 match self.scope_state.variant.unwrap() {
973 Variant::AsyncFunction | Variant::Function if !matches!(func.variant, Variant::Inline) => self.emit_err(
974 TypeCheckerError::can_only_call_inline_function("a `function`, `inline`, or `constructor`", input.span),
975 ),
976 Variant::Transition | Variant::AsyncTransition
977 if matches!(func.variant, Variant::Transition)
978 && input.program.is_none_or(|program| program == self.scope_state.program_name.unwrap()) =>
979 {
980 self.emit_err(TypeCheckerError::cannot_invoke_call_to_local_transition_function(input.span))
981 }
982 _ => {}
983 }
984
985 if func.variant == Variant::Inline
987 && input.program.is_some_and(|program| program != self.scope_state.program_name.unwrap())
988 {
989 self.emit_err(TypeCheckerError::cannot_call_external_inline_function(input.span));
990 }
991
992 if self.async_block_id.is_some() && !matches!(func.variant, Variant::Inline) {
994 self.emit_err(TypeCheckerError::can_only_call_inline_function("an async block", input.span));
995 }
996
997 let mut ret = if func.variant == Variant::AsyncFunction {
999 Type::Future(FutureType::new(
1001 Vec::new(),
1002 Some(Location::new(callee_program, input.function.absolute_path())),
1003 false,
1004 ))
1005 } else if func.variant == Variant::AsyncTransition {
1006 let Some(inputs) =
1008 self.async_function_input_types.get(&Location::new(callee_program, vec![Symbol::intern(&format!(
1009 "finalize/{}",
1010 input.function.identifier().name
1011 ))]))
1012 else {
1013 self.emit_err(TypeCheckerError::async_function_not_found(input.function.clone(), input.span));
1014 return Type::Future(FutureType::new(
1015 Vec::new(),
1016 Some(Location::new(callee_program, callee_path.clone())),
1017 false,
1018 ));
1019 };
1020
1021 let future_type = Type::Future(FutureType::new(
1022 inputs.clone(),
1023 Some(Location::new(callee_program, callee_path.clone())),
1024 true,
1025 ));
1026 let fully_inferred_type = match &func.output_type {
1027 Type::Tuple(tup) => Type::Tuple(TupleType::new(
1028 tup.elements()
1029 .iter()
1030 .map(|t| if matches!(t, Type::Future(_)) { future_type.clone() } else { t.clone() })
1031 .collect::<Vec<Type>>(),
1032 )),
1033 Type::Future(_) => future_type,
1034 _ => panic!("Invalid output type for async transition."),
1035 };
1036 self.assert_and_return_type(fully_inferred_type, expected, input.span())
1037 } else {
1038 self.assert_and_return_type(func.output_type, expected, input.span())
1039 };
1040
1041 if func.input.len() != input.arguments.len() {
1043 self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
1044 func.input.len(),
1045 input.arguments.len(),
1046 input.span(),
1047 ));
1048 }
1049
1050 if func.const_parameters.len() != input.const_arguments.len() {
1052 self.emit_err(TypeCheckerError::incorrect_num_const_args(
1053 "Call",
1054 func.const_parameters.len(),
1055 input.const_arguments.len(),
1056 input.span(),
1057 ));
1058 }
1059
1060 for (expected, argument) in func.const_parameters.iter().zip(input.const_arguments.iter()) {
1062 self.visit_expression(argument, &Some(expected.type_().clone()));
1063 }
1064
1065 let (mut input_futures, mut inferred_finalize_inputs) = (Vec::new(), Vec::new());
1066 for (expected, argument) in func.input.iter().zip(input.arguments.iter()) {
1067 let ty = self.visit_expression(argument, &Some(expected.type_().clone()));
1069
1070 if ty == Type::Err {
1071 return Type::Err;
1072 }
1073 if func.variant == Variant::AsyncFunction && matches!(expected.type_(), Type::Future(_)) {
1075 let option_name = match argument {
1077 Expression::Path(path) => Some(path.identifier().name),
1078 Expression::TupleAccess(tuple_access) => {
1079 if let Expression::Path(path) = &tuple_access.tuple {
1080 Some(path.identifier().name)
1081 } else {
1082 None
1083 }
1084 }
1085 _ => None,
1086 };
1087
1088 if let Some(name) = option_name {
1089 match self.scope_state.futures.shift_remove(&name) {
1090 Some(future) => {
1091 self.scope_state.call_location = Some(future);
1092 }
1093 None => {
1094 self.emit_err(TypeCheckerError::unknown_future_consumed(name, argument.span()));
1095 }
1096 }
1097 }
1098
1099 match argument {
1100 Expression::Path(_) | Expression::Call(_) | Expression::TupleAccess(_) => {
1101 match &self.scope_state.call_location {
1102 Some(location) => {
1103 input_futures.push(location.clone());
1105 inferred_finalize_inputs.push(ty);
1107 }
1108 None => {
1109 self.emit_err(TypeCheckerError::unknown_future_consumed(argument, argument.span()));
1110 }
1111 }
1112 }
1113 _ => {
1114 self.emit_err(TypeCheckerError::unknown_future_consumed("unknown", argument.span()));
1115 }
1116 }
1117 } else {
1118 inferred_finalize_inputs.push(ty);
1119 }
1120 }
1121
1122 let caller_program =
1123 self.scope_state.program_name.expect("`program_name` is always set before traversing a program scope");
1124 let caller_function = if self.scope_state.is_constructor {
1127 sym::constructor
1128 } else {
1129 self.scope_state.function.expect("`function` is always set before traversing a function scope")
1130 };
1131
1132 let caller_path = self
1134 .scope_state
1135 .module_name
1136 .iter()
1137 .cloned()
1138 .chain(std::iter::once(caller_function))
1139 .collect::<Vec<Symbol>>();
1140
1141 let caller = Location::new(caller_program, caller_path.clone());
1142 let callee = Location::new(callee_program, callee_path.clone());
1143 self.state.call_graph.add_edge(caller, callee);
1144
1145 if func.variant.is_transition() && self.scope_state.variant == Some(Variant::AsyncTransition) {
1146 if self.scope_state.has_called_finalize {
1147 self.emit_err(TypeCheckerError::external_call_after_async("function call", input.span));
1148 }
1149
1150 if self.scope_state.already_contains_an_async_block {
1151 self.emit_err(TypeCheckerError::external_call_after_async("block", input.span));
1152 }
1153 }
1154
1155 if func.variant.is_async_function() {
1157 if self.scope_state.is_conditional {
1159 self.emit_err(TypeCheckerError::async_call_in_conditional(input.span));
1160 }
1161
1162 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
1164 self.emit_err(TypeCheckerError::async_call_can_only_be_done_from_async_transition(input.span));
1165 }
1166
1167 if self.scope_state.has_called_finalize {
1169 self.emit_err(TypeCheckerError::must_call_async_function_once(input.span));
1170 }
1171
1172 if self.scope_state.already_contains_an_async_block {
1173 self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
1174 }
1175
1176 if !self.scope_state.futures.is_empty() {
1178 self.emit_err(TypeCheckerError::not_all_futures_consumed(
1179 self.scope_state.futures.iter().map(|(f, _)| f).join(", "),
1180 input.span,
1181 ));
1182 }
1183 self.state
1184 .symbol_table
1185 .attach_finalizer(
1186 Location::new(callee_program, caller_path),
1187 Location::new(callee_program, callee_path.clone()),
1188 input_futures,
1189 inferred_finalize_inputs.clone(),
1190 )
1191 .expect("Failed to attach finalizer");
1192 self.async_function_callers
1194 .entry(Location::new(self.scope_state.program_name.unwrap(), callee_path.clone()))
1195 .or_default()
1196 .insert(self.scope_state.location());
1197
1198 self.scope_state.has_called_finalize = true;
1200
1201 ret = Type::Future(FutureType::new(
1203 inferred_finalize_inputs,
1204 Some(Location::new(callee_program, callee_path.clone())),
1205 true,
1206 ));
1207
1208 self.assert_and_return_type(ret.clone(), expected, input.span());
1210 }
1211
1212 self.scope_state.call_location = Some(Location::new(callee_program, callee_path.clone()));
1214
1215 ret
1216 }
1217
1218 fn visit_cast(&mut self, input: &CastExpression, expected: &Self::AdditionalInput) -> Self::Output {
1219 let expression_type = self.visit_expression_reject_numeric(&input.expression, &None);
1220
1221 let assert_castable_type = |actual: &Type, span: Span| {
1222 if !matches!(
1223 actual,
1224 Type::Integer(_) | Type::Boolean | Type::Field | Type::Group | Type::Scalar | Type::Address | Type::Err,
1225 ) {
1226 self.emit_err(TypeCheckerError::type_should_be2(
1227 actual,
1228 "an integer, bool, field, group, scalar, or address",
1229 span,
1230 ));
1231 }
1232 };
1233
1234 assert_castable_type(&input.type_, input.span());
1235
1236 assert_castable_type(&expression_type, input.expression.span());
1237
1238 self.maybe_assert_type(&input.type_, expected, input.span());
1239
1240 input.type_.clone()
1241 }
1242
1243 fn visit_struct_init(&mut self, input: &StructExpression, additional: &Self::AdditionalInput) -> Self::Output {
1244 let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
1245 let Some(struct_) = struct_ else {
1246 self.emit_err(TypeCheckerError::unknown_sym("struct or record", input.path.clone(), input.path.span()));
1247 return Type::Err;
1248 };
1249
1250 if struct_.const_parameters.len() != input.const_arguments.len() {
1252 self.emit_err(TypeCheckerError::incorrect_num_const_args(
1253 "Struct expression",
1254 struct_.const_parameters.len(),
1255 input.const_arguments.len(),
1256 input.span(),
1257 ));
1258 }
1259
1260 for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
1262 self.visit_expression(argument, &Some(expected.type_().clone()));
1263 }
1264
1265 let type_ = Type::Composite(CompositeType {
1268 path: input.path.clone(),
1269 const_arguments: input.const_arguments.clone(),
1270 program: None,
1271 });
1272 self.maybe_assert_type(&type_, additional, input.path.span());
1273
1274 if struct_.members.len() != input.members.len() {
1276 self.emit_err(TypeCheckerError::incorrect_num_struct_members(
1277 struct_.members.len(),
1278 input.members.len(),
1279 input.span(),
1280 ));
1281 }
1282
1283 for Member { identifier, type_, .. } in struct_.members.iter() {
1284 if let Some(actual) = input.members.iter().find(|member| member.identifier.name == identifier.name) {
1285 match &actual.expression {
1286 None => {
1287 self.visit_expression(
1291 &Path::from(actual.identifier)
1292 .with_absolute_path(Some(
1293 self.scope_state
1294 .module_name
1295 .iter()
1296 .cloned()
1297 .chain(std::iter::once(actual.identifier.name))
1298 .collect::<Vec<Symbol>>(),
1299 ))
1300 .into(),
1301 &Some(type_.clone()),
1302 );
1303 }
1304 Some(expr) => {
1305 self.visit_expression(expr, &Some(type_.clone()));
1307 }
1308 };
1309 } else {
1310 self.emit_err(TypeCheckerError::missing_struct_member(struct_.identifier, identifier, input.span()));
1311 };
1312 }
1313
1314 if struct_.is_record {
1315 if self.scope_state.variant == Some(Variant::AsyncFunction) {
1318 self.state
1319 .handler
1320 .emit_err(TypeCheckerError::records_not_allowed_inside_async("function", input.span()));
1321 }
1322
1323 if self.async_block_id.is_some() {
1326 self.state.handler.emit_err(TypeCheckerError::records_not_allowed_inside_async("block", input.span()));
1327 }
1328
1329 input.members.iter().filter(|init| init.identifier.name == sym::owner).for_each(|init| {
1334 if let Some(Expression::Intrinsic(intr)) = &init.expression
1335 && let IntrinsicExpression { name: sym::_self_caller, .. } = &**intr
1336 {
1337 self.emit_warning(TypeCheckerWarning::caller_as_record_owner(input.path.clone(), intr.span()));
1338 }
1339 });
1340 }
1341
1342 type_
1343 }
1344
1345 fn visit_err(&mut self, _input: &ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1347 Type::Err
1348 }
1349
1350 fn visit_path(&mut self, input: &Path, expected: &Self::AdditionalInput) -> Self::Output {
1351 let var = self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path());
1352
1353 if let Some(var) = var {
1354 if var.declaration == VariableType::Storage && !var.type_.is_vector() && !var.type_.is_mapping() {
1355 self.check_access_allowed("storage access", true, input.span());
1356 }
1357
1358 self.maybe_assert_type(&var.type_, expected, input.span());
1359 var.type_.clone()
1360 } else {
1361 self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span()));
1362 Type::Err
1363 }
1364 }
1365
1366 fn visit_literal(&mut self, input: &Literal, expected: &Self::AdditionalInput) -> Self::Output {
1367 let span = input.span();
1368
1369 macro_rules! parse_and_return {
1370 ($ty:ty, $variant:expr, $str:expr, $label:expr) => {{
1371 self.parse_integer_literal::<$ty>($str, span, $label);
1372 Type::Integer($variant)
1373 }};
1374 }
1375
1376 let type_ = match &input.variant {
1377 LiteralVariant::Address(..) => Type::Address,
1378 LiteralVariant::Boolean(..) => Type::Boolean,
1379 LiteralVariant::Field(..) => Type::Field,
1380 LiteralVariant::Scalar(..) => Type::Scalar,
1381 LiteralVariant::String(..) => Type::String,
1382 LiteralVariant::Integer(kind, string) => match kind {
1383 IntegerType::U8 => parse_and_return!(u8, IntegerType::U8, string, "u8"),
1384 IntegerType::U16 => parse_and_return!(u16, IntegerType::U16, string, "u16"),
1385 IntegerType::U32 => parse_and_return!(u32, IntegerType::U32, string, "u32"),
1386 IntegerType::U64 => parse_and_return!(u64, IntegerType::U64, string, "u64"),
1387 IntegerType::U128 => parse_and_return!(u128, IntegerType::U128, string, "u128"),
1388 IntegerType::I8 => parse_and_return!(i8, IntegerType::I8, string, "i8"),
1389 IntegerType::I16 => parse_and_return!(i16, IntegerType::I16, string, "i16"),
1390 IntegerType::I32 => parse_and_return!(i32, IntegerType::I32, string, "i32"),
1391 IntegerType::I64 => parse_and_return!(i64, IntegerType::I64, string, "i64"),
1392 IntegerType::I128 => parse_and_return!(i128, IntegerType::I128, string, "i128"),
1393 },
1394 LiteralVariant::Group(s) => {
1395 let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1396 if !trimmed.is_empty()
1397 && format!("{trimmed}group")
1398 .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1399 .is_err()
1400 {
1401 self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1402 }
1403 Type::Group
1404 }
1405 LiteralVariant::Unsuffixed(_) => match expected {
1406 Some(ty @ Type::Integer(_) | ty @ Type::Field | ty @ Type::Group | ty @ Type::Scalar) => {
1407 self.check_numeric_literal(input, ty);
1408 ty.clone()
1409 }
1410 Some(ty @ Type::Optional(opt)) => {
1411 let inner = &opt.inner;
1413 match &**inner {
1414 Type::Integer(_) | Type::Field | Type::Group | Type::Scalar => {
1415 self.check_numeric_literal(input, inner);
1416 *inner.clone()
1417 }
1418 _ => {
1419 self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(
1420 format!("type `{ty}`"),
1421 span,
1422 ));
1423 Type::Err
1424 }
1425 }
1426 }
1427 Some(ty) => {
1428 self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(format!("type `{ty}`"), span));
1429 Type::Err
1430 }
1431 None => Type::Numeric,
1432 },
1433 LiteralVariant::None => {
1434 if let Some(ty @ Type::Optional(_)) = expected {
1435 ty.clone()
1436 } else if let Some(ty) = expected {
1437 self.emit_err(TypeCheckerError::none_found_non_optional(format!("{ty}"), span));
1438 Type::Err
1439 } else {
1440 self.emit_err(TypeCheckerError::could_not_determine_type(format!("{input}"), span));
1441 Type::Err
1442 }
1443 }
1444 };
1445
1446 self.maybe_assert_type(&type_, expected, span);
1447
1448 type_
1449 }
1450
1451 fn visit_locator(&mut self, input: &LocatorExpression, expected: &Self::AdditionalInput) -> Self::Output {
1452 let maybe_var =
1453 self.state.symbol_table.lookup_global(&Location::new(input.program.name.name, vec![input.name])).cloned();
1454 if let Some(var) = maybe_var {
1455 self.maybe_assert_type(&var.type_, expected, input.span());
1456 var.type_
1457 } else {
1458 self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));
1459 Type::Err
1460 }
1461 }
1462
1463 fn visit_ternary(&mut self, input: &TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
1464 self.visit_expression(&input.condition, &Some(Type::Boolean));
1465
1466 let (t1, t2) = if expected.is_some() {
1468 (
1469 self.visit_expression_reject_numeric(&input.if_true, expected),
1470 self.visit_expression_reject_numeric(&input.if_false, expected),
1471 )
1472 } else if input.if_false.is_none_expr() {
1473 let t1 = self.visit_expression(&input.if_true, &None);
1474 if matches!(t1, Type::Optional(_)) {
1475 (t1.clone(), self.visit_expression(&input.if_false, &Some(t1.clone())))
1476 } else {
1477 (
1478 t1.clone(),
1479 self.visit_expression(
1480 &input.if_false,
1481 &Some(Type::Optional(OptionalType { inner: Box::new(t1.clone()) })),
1482 ),
1483 )
1484 }
1485 } else if input.if_true.is_none_expr() {
1486 let t2 = self.visit_expression(&input.if_false, &None);
1487 if matches!(t2, Type::Optional(_)) {
1488 (t2.clone(), self.visit_expression(&input.if_true, &Some(t2.clone())))
1489 } else {
1490 (
1491 t2.clone(),
1492 self.visit_expression(
1493 &input.if_true,
1494 &Some(Type::Optional(OptionalType { inner: Box::new(t2.clone()) })),
1495 ),
1496 )
1497 }
1498 } else {
1499 (
1500 self.visit_expression_reject_numeric(&input.if_true, &None),
1501 self.visit_expression_reject_numeric(&input.if_false, &None),
1502 )
1503 };
1504
1505 let typ = if t1 == Type::Err || t2 == Type::Err {
1506 Type::Err
1507 } else if !t1.can_coerce_to(&t2) && !t2.can_coerce_to(&t1) {
1508 self.emit_err(TypeCheckerError::ternary_branch_mismatch(t1, t2, input.span()));
1509 Type::Err
1510 } else if let Some(expected) = expected {
1511 expected.clone()
1512 } else if t1.can_coerce_to(&t2) {
1513 t2
1514 } else {
1515 t1
1516 };
1517
1518 if self.is_external_record(&typ) {
1520 self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1521 }
1522
1523 if let Type::Tuple(tuple) = &typ
1525 && tuple.elements().iter().any(|ty| self.is_external_record(ty))
1526 {
1527 self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1528 }
1529
1530 typ
1531 }
1532
1533 fn visit_tuple(&mut self, input: &TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
1534 if let Some(expected) = expected {
1535 if let Type::Tuple(expected_types) = expected {
1536 if expected_types.length() != input.elements.len() {
1540 self.emit_err(TypeCheckerError::incorrect_tuple_length(
1541 expected_types.length(),
1542 input.elements.len(),
1543 input.span(),
1544 ));
1545 }
1546
1547 input.elements.iter().zip(expected_types.elements()).for_each(|(expr, expected_el_ty)| {
1549 if matches!(expr, Expression::Tuple(_)) {
1550 self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1551 }
1552 self.visit_expression(expr, &Some(expected_el_ty.clone()));
1553 });
1554
1555 expected.clone()
1557 } else {
1558 let field_types = input
1562 .elements
1563 .iter()
1564 .map(|field| {
1565 let ty = self.visit_expression(field, &None);
1566 if ty == Type::Numeric {
1567 self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1568 Type::Err
1569 } else {
1570 ty
1571 }
1572 })
1573 .collect::<Vec<_>>();
1574 if field_types.iter().all(|f| *f != Type::Err) {
1575 let tuple_type = Type::Tuple(TupleType::new(field_types));
1576 self.emit_err(TypeCheckerError::type_should_be2(tuple_type, expected, input.span()));
1577 }
1578
1579 expected.clone()
1581 }
1582 } else {
1583 input.elements.iter().for_each(|expr| {
1587 if matches!(expr, Expression::Tuple(_)) {
1588 self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1589 }
1590 });
1591
1592 Type::Tuple(TupleType::new(
1593 input
1594 .elements
1595 .iter()
1596 .map(|field| {
1597 let ty = self.visit_expression(field, &None);
1598 if ty == Type::Numeric {
1599 self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1600 Type::Err
1601 } else {
1602 ty
1603 }
1604 })
1605 .collect::<Vec<_>>(),
1606 ))
1607 }
1608 }
1609
1610 fn visit_unary(&mut self, input: &UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
1611 let operand_expected = self.unwrap_optional_type(destination);
1612
1613 let assert_signed_int = |slf: &mut Self, type_: &Type| {
1614 if !matches!(
1615 type_,
1616 Type::Err
1617 | Type::Integer(IntegerType::I8)
1618 | Type::Integer(IntegerType::I16)
1619 | Type::Integer(IntegerType::I32)
1620 | Type::Integer(IntegerType::I64)
1621 | Type::Integer(IntegerType::I128)
1622 ) {
1623 slf.emit_err(TypeCheckerError::type_should_be2(type_, "a signed integer", input.span()));
1624 }
1625 };
1626
1627 let ty = match input.op {
1628 UnaryOperation::Abs => {
1629 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1630 assert_signed_int(self, &type_);
1631 type_
1632 }
1633 UnaryOperation::AbsWrapped => {
1634 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1635 assert_signed_int(self, &type_);
1636 type_
1637 }
1638 UnaryOperation::Double => {
1639 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1640 if !matches!(&type_, Type::Err | Type::Field | Type::Group) {
1641 self.emit_err(TypeCheckerError::type_should_be2(&type_, "a field or group", input.span()));
1642 }
1643 type_
1644 }
1645 UnaryOperation::Inverse => {
1646 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1647 if type_ == Type::Numeric {
1648 type_ = Type::Field;
1650 self.state.type_table.insert(input.receiver.id(), Type::Field);
1651 } else {
1652 self.assert_type(&type_, &Type::Field, input.span());
1653 }
1654 type_
1655 }
1656 UnaryOperation::Negate => {
1657 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1658 if !matches!(
1659 &type_,
1660 Type::Err
1661 | Type::Integer(IntegerType::I8)
1662 | Type::Integer(IntegerType::I16)
1663 | Type::Integer(IntegerType::I32)
1664 | Type::Integer(IntegerType::I64)
1665 | Type::Integer(IntegerType::I128)
1666 | Type::Group
1667 | Type::Field
1668 ) {
1669 self.emit_err(TypeCheckerError::type_should_be2(
1670 &type_,
1671 "a signed integer, group, or field",
1672 input.receiver.span(),
1673 ));
1674 }
1675 type_
1676 }
1677 UnaryOperation::Not => {
1678 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1679 if !matches!(&type_, Type::Err | Type::Boolean | Type::Integer(_)) {
1680 self.emit_err(TypeCheckerError::type_should_be2(&type_, "a bool or integer", input.span()));
1681 }
1682 type_
1683 }
1684 UnaryOperation::Square => {
1685 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1686 if type_ == Type::Numeric {
1687 type_ = Type::Field;
1689 self.state.type_table.insert(input.receiver.id(), Type::Field);
1690 } else {
1691 self.assert_type(&type_, &Type::Field, input.span());
1692 }
1693 type_
1694 }
1695 UnaryOperation::SquareRoot => {
1696 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1697 if type_ == Type::Numeric {
1698 type_ = Type::Field;
1700 self.state.type_table.insert(input.receiver.id(), Type::Field);
1701 } else {
1702 self.assert_type(&type_, &Type::Field, input.span());
1703 }
1704 type_
1705 }
1706 UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
1707 let _operand_type = self.visit_expression(&input.receiver, &Some(Type::Group));
1708 self.maybe_assert_type(&Type::Field, destination, input.span());
1709 Type::Field
1710 }
1711 };
1712
1713 self.maybe_assert_type(&ty, destination, input.span());
1714
1715 ty
1716 }
1717
1718 fn visit_unit(&mut self, _input: &UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1719 Type::Unit
1720 }
1721
1722 fn visit_statement(&mut self, input: &Statement) {
1724 if self.scope_state.has_return {
1726 self.emit_err(TypeCheckerError::unreachable_code_after_return(input.span()));
1727 return;
1728 }
1729
1730 match input {
1731 Statement::Assert(stmt) => self.visit_assert(stmt),
1732 Statement::Assign(stmt) => self.visit_assign(stmt),
1733 Statement::Block(stmt) => self.visit_block(stmt),
1734 Statement::Conditional(stmt) => self.visit_conditional(stmt),
1735 Statement::Const(stmt) => self.visit_const(stmt),
1736 Statement::Definition(stmt) => self.visit_definition(stmt),
1737 Statement::Expression(stmt) => self.visit_expression_statement(stmt),
1738 Statement::Iteration(stmt) => self.visit_iteration(stmt),
1739 Statement::Return(stmt) => self.visit_return(stmt),
1740 }
1741 }
1742
1743 fn visit_assert(&mut self, input: &AssertStatement) {
1744 match &input.variant {
1745 AssertVariant::Assert(expr) => {
1746 let _type = self.visit_expression(expr, &Some(Type::Boolean));
1747 }
1748 AssertVariant::AssertEq(left, right) | AssertVariant::AssertNeq(left, right) => {
1749 let t1 = self.visit_expression_reject_numeric(left, &None);
1750 let t2 = self.visit_expression_reject_numeric(right, &None);
1751
1752 if t1 != Type::Err && t2 != Type::Err && !t1.eq_user(&t2) {
1753 let op =
1754 if matches!(input.variant, AssertVariant::AssertEq(..)) { "assert_eq" } else { "assert_neq" };
1755 self.emit_err(TypeCheckerError::operation_types_mismatch(op, t1, t2, input.span()));
1756 }
1757 }
1758 }
1759 }
1760
1761 fn visit_assign(&mut self, input: &AssignStatement) {
1762 let (lhs_type, is_storage) = self.visit_expression_assign(&input.place);
1763 let value = &input.value;
1764
1765 if lhs_type == Type::Err {
1766 self.visit_expression(value, &None);
1767 return;
1768 }
1769
1770 if is_storage && !lhs_type.is_vector() && !lhs_type.is_mapping() {
1771 self.check_access_allowed("storage write", true, input.place.span())
1772 }
1773
1774 let expected_rhs_ty = match (is_storage, value.is_none_expr(), &lhs_type) {
1775 (true, false, Type::Optional(OptionalType { inner })) => {
1776 Some(*inner.clone())
1792 }
1793 _ => {
1794 Some(lhs_type)
1796 }
1797 };
1798
1799 self.visit_expression(value, &expected_rhs_ty);
1800 }
1801
1802 fn visit_block(&mut self, input: &Block) {
1803 self.in_scope(input.id, |slf| {
1804 input.statements.iter().for_each(|stmt| slf.visit_statement(stmt));
1805 });
1806 }
1807
1808 fn visit_conditional(&mut self, input: &ConditionalStatement) {
1809 self.visit_expression(&input.condition, &Some(Type::Boolean));
1810
1811 let mut then_block_has_return = false;
1812 let mut otherwise_block_has_return = false;
1813
1814 let previous_has_return = core::mem::replace(&mut self.scope_state.has_return, then_block_has_return);
1816 let previous_is_conditional = core::mem::replace(&mut self.scope_state.is_conditional, true);
1818
1819 self.in_conditional_scope(|slf| slf.visit_block(&input.then));
1821
1822 then_block_has_return = self.scope_state.has_return;
1824
1825 if let Some(otherwise) = &input.otherwise {
1826 self.scope_state.has_return = otherwise_block_has_return;
1828
1829 match &**otherwise {
1830 Statement::Block(stmt) => {
1831 self.in_conditional_scope(|slf| slf.visit_block(stmt));
1833 }
1834 Statement::Conditional(stmt) => self.visit_conditional(stmt),
1835 _ => unreachable!("Else-case can only be a block or conditional statement."),
1836 }
1837
1838 otherwise_block_has_return = self.scope_state.has_return;
1840 }
1841
1842 self.scope_state.has_return = previous_has_return || (then_block_has_return && otherwise_block_has_return);
1844 self.scope_state.is_conditional = previous_is_conditional;
1846 }
1847
1848 fn visit_const(&mut self, input: &ConstDeclaration) {
1849 self.visit_type(&input.type_);
1850
1851 if self.contains_optional_type(&input.type_) {
1854 self.emit_err(TypeCheckerError::const_cannot_be_optional(input.span));
1855 }
1856
1857 match &input.type_ {
1859 Type::Unit => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.span)),
1861 Type::Tuple(tuple) => match tuple.length() {
1863 0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
1864 _ => {
1865 if tuple.elements().iter().any(|type_| matches!(type_, Type::Tuple(_))) {
1866 self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
1867 }
1868 }
1869 },
1870 Type::Mapping(_) | Type::Err => unreachable!(
1871 "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
1872 ),
1873 _ => (), }
1876
1877 self.visit_expression(&input.value, &Some(input.type_.clone()));
1879
1880 if self.scope_state.function.is_some() {
1881 if let Err(err) = self.state.symbol_table.insert_variable(
1884 self.scope_state.program_name.unwrap(),
1885 &[input.place.name],
1886 VariableSymbol { type_: input.type_.clone(), span: input.place.span, declaration: VariableType::Const },
1887 ) {
1888 self.state.handler.emit_err(err);
1889 }
1890 }
1891 }
1892
1893 fn visit_definition(&mut self, input: &DefinitionStatement) {
1894 if let Some(ty) = &input.type_ {
1896 self.visit_type(ty);
1897 self.assert_type_is_valid(ty, input.span);
1898 }
1899
1900 match &input.type_ {
1902 Some(Type::Tuple(tuple)) => match tuple.length() {
1904 0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
1905 _ => {
1906 for type_ in tuple.elements() {
1907 if matches!(type_, Type::Tuple(_)) {
1908 self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
1909 }
1910 }
1911 }
1912 },
1913 Some(Type::Mapping(_)) | Some(Type::Err) => unreachable!(
1914 "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
1915 ),
1916 _ => (), }
1919
1920 let inferred_type = self.visit_expression_reject_numeric(&input.value, &input.type_);
1924
1925 if inferred_type.is_vector() {
1928 self.emit_err(TypeCheckerError::storage_vectors_cannot_be_moved_or_assigned(input.value.span()));
1929 }
1930
1931 match &input.place {
1933 DefinitionPlace::Single(identifier) => {
1934 self.insert_variable(
1935 Some(inferred_type.clone()),
1936 identifier,
1937 input.type_.clone().unwrap_or(inferred_type),
1939 identifier.span,
1940 );
1941 }
1942 DefinitionPlace::Multiple(identifiers) => {
1943 let tuple_type = match (&input.type_, inferred_type.clone()) {
1945 (Some(Type::Tuple(tuple_type)), _) => tuple_type.clone(),
1946 (None, Type::Tuple(tuple_type)) => tuple_type.clone(),
1947 _ => {
1948 return;
1950 }
1951 };
1952
1953 if identifiers.len() != tuple_type.length() {
1956 return self.emit_err(TypeCheckerError::incorrect_num_tuple_elements(
1957 identifiers.len(),
1958 tuple_type.length(),
1959 input.span(),
1960 ));
1961 }
1962
1963 for (i, identifier) in identifiers.iter().enumerate() {
1965 let inferred = if let Type::Tuple(inferred_tuple) = &inferred_type {
1966 inferred_tuple.elements().get(i).cloned().unwrap_or_default()
1967 } else {
1968 Type::Err
1969 };
1970 self.insert_variable(Some(inferred), identifier, tuple_type.elements()[i].clone(), identifier.span);
1971 }
1972 }
1973 }
1974 }
1975
1976 fn visit_expression_statement(&mut self, input: &ExpressionStatement) {
1977 if !matches!(input.expression, Expression::Call(_) | Expression::Intrinsic(_) | Expression::Unit(_)) {
1979 self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
1980 } else {
1981 self.visit_expression(&input.expression, &None);
1983 }
1984 }
1985
1986 fn visit_iteration(&mut self, input: &IterationStatement) {
1987 if let Some(ty) = &input.type_ {
1989 self.visit_type(ty);
1990 self.assert_int_type(ty, input.variable.span);
1991 }
1992
1993 let start_ty = self.visit_expression(&input.start, &input.type_.clone());
1996 let stop_ty = self.visit_expression(&input.stop, &input.type_.clone());
1997
1998 self.assert_int_type(&start_ty, input.start.span());
2000 self.assert_int_type(&stop_ty, input.stop.span());
2001
2002 if start_ty != stop_ty {
2003 self.emit_err(TypeCheckerError::range_bounds_type_mismatch(input.start.span() + input.stop.span()));
2005 }
2006
2007 let iterator_ty = input.type_.clone().unwrap_or(start_ty);
2011 self.state.type_table.insert(input.variable.id(), iterator_ty.clone());
2012
2013 self.in_scope(input.id(), |slf| {
2014 if let Err(err) = slf.state.symbol_table.insert_variable(
2016 slf.scope_state.program_name.unwrap(),
2017 &[input.variable.name],
2018 VariableSymbol { type_: iterator_ty.clone(), span: input.span(), declaration: VariableType::Const },
2019 ) {
2020 slf.state.handler.emit_err(err);
2021 }
2022
2023 let prior_has_return = core::mem::take(&mut slf.scope_state.has_return);
2024 let prior_has_finalize = core::mem::take(&mut slf.scope_state.has_called_finalize);
2025
2026 slf.visit_block(&input.block);
2027
2028 if slf.scope_state.has_return {
2029 slf.emit_err(TypeCheckerError::loop_body_contains_return(input.span()));
2030 }
2031
2032 if slf.scope_state.has_called_finalize {
2033 slf.emit_err(TypeCheckerError::loop_body_contains_async("function call", input.span()));
2034 }
2035
2036 if slf.scope_state.already_contains_an_async_block {
2037 slf.emit_err(TypeCheckerError::loop_body_contains_async("block expression", input.span()));
2038 }
2039
2040 slf.scope_state.has_return = prior_has_return;
2041 slf.scope_state.has_called_finalize = prior_has_finalize;
2042 });
2043 }
2044
2045 fn visit_return(&mut self, input: &ReturnStatement) {
2046 if self.async_block_id.is_some() {
2047 return self.emit_err(TypeCheckerError::async_block_cannot_return(input.span()));
2048 }
2049
2050 if self.scope_state.is_constructor {
2051 if !matches!(input.expression, Expression::Unit(..)) {
2053 self.emit_err(TypeCheckerError::constructor_can_only_return_unit(&input.expression, input.span));
2054 }
2055 return;
2056 }
2057
2058 let caller_name = self.scope_state.function.expect("`self.function` is set every time a function is visited.");
2059 let caller_path =
2060 self.scope_state.module_name.iter().cloned().chain(std::iter::once(caller_name)).collect::<Vec<Symbol>>();
2061
2062 let func_symbol = self
2063 .state
2064 .symbol_table
2065 .lookup_function(&Location::new(self.scope_state.program_name.unwrap(), caller_path.clone()))
2066 .expect("The symbol table creator should already have visited all functions.");
2067
2068 let mut return_type = func_symbol.function.output_type.clone();
2069
2070 if self.scope_state.variant == Some(Variant::AsyncTransition) && self.scope_state.has_called_finalize {
2071 let inferred_future_type = Future(FutureType::new(
2072 if let Some(finalizer) = &func_symbol.finalizer { finalizer.inferred_inputs.clone() } else { vec![] },
2073 Some(Location::new(self.scope_state.program_name.unwrap(), caller_path)),
2074 true,
2075 ));
2076
2077 let inferred = match return_type.clone() {
2080 Future(_) => inferred_future_type,
2081 Tuple(tuple) => Tuple(TupleType::new(
2082 tuple
2083 .elements()
2084 .iter()
2085 .map(|t| if matches!(t, Future(_)) { inferred_future_type.clone() } else { t.clone() })
2086 .collect::<Vec<Type>>(),
2087 )),
2088 _ => {
2089 return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
2090 }
2091 };
2092
2093 return_type = self.assert_and_return_type(inferred, &Some(return_type), input.span());
2095 }
2096
2097 if matches!(input.expression, Expression::Unit(..)) {
2098 if return_type != Type::Unit {
2100 return self.emit_err(TypeCheckerError::missing_return(input.span()));
2104 }
2105 }
2106
2107 self.visit_expression(&input.expression, &Some(return_type));
2108
2109 self.scope_state.has_return = true;
2112 }
2113}