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 if !assign {
132 match &input.inner {
133 Expression::Path(path) if path.identifier().name == sym::SelfLower => {
135 match input.name.name {
136 sym::address => {
137 let ty = Type::Address;
138 self.maybe_assert_type(&ty, expected, input.span());
139 return ty;
140 }
141 sym::caller => {
142 self.check_access_allowed("self.caller", false, input.name.span());
144
145 let ty = Type::Address;
146 self.maybe_assert_type(&ty, expected, input.span());
147 return ty;
148 }
149 sym::checksum => {
150 let ty = Type::Array(ArrayType::new(
151 Type::Integer(IntegerType::U8),
152 Expression::Literal(Literal::integer(
153 IntegerType::U8,
154 "32".to_string(),
155 Default::default(),
156 Default::default(),
157 )),
158 ));
159 self.maybe_assert_type(&ty, expected, input.span());
160 return ty;
161 }
162 sym::edition => {
163 let ty = Type::Integer(IntegerType::U16);
164 self.maybe_assert_type(&ty, expected, input.span());
165 return ty;
166 }
167 sym::id => {
168 let ty = Type::Address;
169 self.maybe_assert_type(&ty, expected, input.span());
170 return ty;
171 }
172 sym::program_owner => {
173 self.check_access_allowed("self.program_owner", true, input.name.span());
175
176 let ty = Type::Address;
177 self.maybe_assert_type(&ty, expected, input.span());
178 return ty;
179 }
180 sym::signer => {
181 self.check_access_allowed("self.signer", false, input.name.span());
183
184 let ty = Type::Address;
185 self.maybe_assert_type(&ty, expected, input.span());
186 return ty;
187 }
188 _ => {
189 self.emit_err(TypeCheckerError::invalid_self_access(input.name.span()));
190 return Type::Err;
191 }
192 }
193 }
194 Expression::Path(path) if path.identifier().name == sym::block => match input.name.name {
196 sym::height => {
197 self.check_access_allowed("block.height", true, input.name.span());
199 let ty = Type::Integer(IntegerType::U32);
200 self.maybe_assert_type(&ty, expected, input.span());
201 return ty;
202 }
203 sym::timestamp => {
204 self.check_access_allowed("block.timestamp", true, input.name.span());
206 let ty = Type::Integer(IntegerType::I64);
207 self.maybe_assert_type(&ty, expected, input.span());
208 return ty;
209 }
210 _ => {
211 self.emit_err(TypeCheckerError::invalid_block_access(input.name.span()));
212 return Type::Err;
213 }
214 },
215 Expression::Path(path) if path.identifier().name == sym::network => match input.name.name {
217 sym::id => {
218 self.check_access_allowed("network.id", true, input.name.span());
220 let ty = Type::Integer(IntegerType::U16);
221 self.maybe_assert_type(&ty, expected, input.span());
222 return ty;
223 }
224 _ => {
225 self.emit_err(TypeCheckerError::invalid_block_access(input.name.span()));
226 return Type::Err;
227 }
228 },
229 _ => {}
230 }
231 }
232
233 let ty = if assign {
234 self.visit_expression_assign(&input.inner).0
235 } else {
236 self.visit_expression(&input.inner, &None)
237 };
238
239 if assign && self.is_external_record(&ty) {
241 self.emit_err(TypeCheckerError::assignment_to_external_record_member(&ty, input.span));
242 }
243
244 match ty {
246 Type::Err => Type::Err,
247 Type::Composite(ref struct_) => {
248 let Some(struct_) = self
250 .lookup_struct(struct_.program.or(self.scope_state.program_name), &struct_.path.absolute_path())
251 else {
252 self.emit_err(TypeCheckerError::undefined_type(ty, input.inner.span()));
253 return Type::Err;
254 };
255 match struct_.members.iter().find(|member| member.name() == input.name.name) {
257 Some(Member { type_, .. }) => {
259 self.maybe_assert_type(type_, expected, input.span());
261 type_.clone()
262 }
263 None => {
265 self.emit_err(TypeCheckerError::invalid_struct_variable(
266 input.name,
267 &struct_,
268 input.name.span(),
269 ));
270 Type::Err
271 }
272 }
273 }
274 type_ => {
275 self.emit_err(TypeCheckerError::type_should_be2(type_, "a struct or record", input.inner.span()));
276 Type::Err
277 }
278 }
279 }
280
281 pub fn visit_tuple_access_general(&mut self, input: &TupleAccess, assign: bool, expected: &Option<Type>) -> Type {
282 let this_type = if assign {
283 self.visit_expression_assign(&input.tuple).0
284 } else {
285 self.visit_expression(&input.tuple, &None)
286 };
287 match this_type {
288 Type::Err => Type::Err,
289 Type::Tuple(tuple) => {
290 let index = input.index.value();
292 let Some(actual) = tuple.elements().get(index) else {
293 self.emit_err(TypeCheckerError::tuple_out_of_range(index, tuple.length(), input.span()));
294 return Type::Err;
295 };
296
297 self.maybe_assert_type(actual, expected, input.span());
298
299 actual.clone()
300 }
301 Type::Future(_) => {
302 let Some(Type::Future(inferred_f)) = self.state.type_table.get(&input.tuple.id()) else {
304 return Type::Err;
306 };
307
308 if inferred_f.location.is_none() {
309 self.emit_err(TypeCheckerError::invalid_async_block_future_access(input.span()));
312 return Type::Err;
313 }
314
315 let Some(actual) = inferred_f.inputs().get(input.index.value()) else {
316 self.emit_err(TypeCheckerError::invalid_future_access(
317 input.index.value(),
318 inferred_f.inputs().len(),
319 input.span(),
320 ));
321 return Type::Err;
322 };
323
324 if let Type::Err = actual {
326 self.emit_err(TypeCheckerError::future_error_member(input.index.value(), input.span()));
327 return Type::Err;
328 }
329
330 self.maybe_assert_type(actual, expected, input.span());
331
332 actual.clone()
333 }
334 type_ => {
335 self.emit_err(TypeCheckerError::type_should_be2(type_, "a tuple or future", input.span()));
336 Type::Err
337 }
338 }
339 }
340
341 pub fn visit_path_assign(&mut self, input: &Path) -> (Type, bool) {
344 let Some(var) =
346 self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path())
347 else {
348 self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span));
349 return (Type::Err, false);
350 };
351
352 if var.type_.is_vector() {
354 self.emit_err(TypeCheckerError::invalid_assignment_target(input, input.span()));
355 return (Type::Err, false);
356 }
357
358 match &var.declaration {
360 VariableType::Const => self.emit_err(TypeCheckerError::cannot_assign_to_const_var(input, var.span)),
361 VariableType::ConstParameter => {
362 self.emit_err(TypeCheckerError::cannot_assign_to_generic_const_function_parameter(input, input.span))
363 }
364 VariableType::Input(Mode::Constant) => {
365 self.emit_err(TypeCheckerError::cannot_assign_to_const_input(input, var.span))
366 }
367 VariableType::Storage => return (var.type_.clone(), true),
368 VariableType::Mut | VariableType::Input(_) => {}
369 }
370
371 if self.scope_state.variant.unwrap().is_async_function()
373 && !self.symbol_in_conditional_scope(input.identifier().name)
374 {
375 self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "function", var.span));
376 }
377
378 if self.async_block_id.is_some() && !self.symbol_in_conditional_scope(input.identifier().name) {
380 self.emit_err(TypeCheckerError::async_cannot_assign_outside_conditional(input, "block", var.span));
381 }
382
383 if let Some(async_block_id) = self.async_block_id
384 && !self.state.symbol_table.is_defined_in_scope_or_ancestor_until(async_block_id, input.identifier().name)
385 {
386 self.emit_err(TypeCheckerError::cannot_assign_to_vars_outside_async_block(
390 input.identifier().name,
391 input.span,
392 ));
393 }
394
395 (var.type_.clone(), false)
396 }
397
398 pub(crate) fn visit_expression_reject_numeric(&mut self, expr: &Expression, expected: &Option<Type>) -> Type {
401 let mut inferred = self.visit_expression(expr, expected);
402 match inferred {
403 Type::Numeric => {
404 self.emit_inference_failure_error(&mut inferred, expr);
405 Type::Err
406 }
407 _ => inferred,
408 }
409 }
410
411 pub(crate) fn visit_expression_infer_default_u32(&mut self, expr: &Expression) -> Type {
414 let mut inferred = self.visit_expression(expr, &None);
415
416 if inferred == Type::Numeric {
417 inferred = Type::Integer(IntegerType::U32);
418
419 if let Expression::Literal(literal) = expr
420 && !self.check_numeric_literal(literal, &inferred)
421 {
422 inferred = Type::Err;
423 }
424
425 self.state.type_table.insert(expr.id(), inferred.clone());
426 }
427
428 inferred
429 }
430}
431
432impl AstVisitor for TypeCheckingVisitor<'_> {
433 type AdditionalInput = Option<Type>;
434 type Output = Type;
435
436 fn visit_array_type(&mut self, input: &ArrayType) {
438 self.visit_type(&input.element_type);
439 self.visit_expression_infer_default_u32(&input.length);
440 }
441
442 fn visit_composite_type(&mut self, input: &CompositeType) {
443 let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
444
445 if let Some(struct_) = struct_ {
446 if struct_.const_parameters.len() != input.const_arguments.len() {
448 self.emit_err(TypeCheckerError::incorrect_num_const_args(
449 "Struct type",
450 struct_.const_parameters.len(),
451 input.const_arguments.len(),
452 input.path.span,
453 ));
454 }
455
456 for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
458 self.visit_expression(argument, &Some(expected.type_().clone()));
459 }
460 } else if !input.const_arguments.is_empty() {
461 self.emit_err(TypeCheckerError::unexpected_const_args(input, input.path.span));
462 }
463 }
464
465 fn visit_expression(&mut self, input: &Expression, additional: &Self::AdditionalInput) -> Self::Output {
467 let output = match input {
468 Expression::Array(array) => self.visit_array(array, additional),
469 Expression::ArrayAccess(access) => self.visit_array_access_general(access, false, additional),
470 Expression::AssociatedConstant(constant) => self.visit_associated_constant(constant, additional),
471 Expression::AssociatedFunction(function) => self.visit_associated_function(function, additional),
472 Expression::Async(async_) => self.visit_async(async_, additional),
473 Expression::Binary(binary) => self.visit_binary(binary, additional),
474 Expression::Call(call) => self.visit_call(call, additional),
475 Expression::Cast(cast) => self.visit_cast(cast, additional),
476 Expression::Struct(struct_) => self.visit_struct_init(struct_, additional),
477 Expression::Err(err) => self.visit_err(err, additional),
478 Expression::Path(path) => self.visit_path(path, additional),
479 Expression::Literal(literal) => self.visit_literal(literal, additional),
480 Expression::Locator(locator) => self.visit_locator(locator, additional),
481 Expression::MemberAccess(access) => self.visit_member_access_general(access, false, additional),
482 Expression::Repeat(repeat) => self.visit_repeat(repeat, additional),
483 Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
484 Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
485 Expression::TupleAccess(access) => self.visit_tuple_access_general(access, false, additional),
486 Expression::Unary(unary) => self.visit_unary(unary, additional),
487 Expression::Unit(unit) => self.visit_unit(unit, additional),
488 };
489
490 self.state.type_table.insert(input.id(), output.clone());
492 output
493 }
494
495 fn visit_array_access(&mut self, _input: &ArrayAccess, _additional: &Self::AdditionalInput) -> Self::Output {
496 panic!("Should not be called.");
497 }
498
499 fn visit_member_access(&mut self, _input: &MemberAccess, _additional: &Self::AdditionalInput) -> Self::Output {
500 panic!("Should not be called.");
501 }
502
503 fn visit_tuple_access(&mut self, _input: &TupleAccess, _additional: &Self::AdditionalInput) -> Self::Output {
504 panic!("Should not be called.");
505 }
506
507 fn visit_array(&mut self, input: &ArrayExpression, additional: &Self::AdditionalInput) -> Self::Output {
508 let element_type = match additional {
511 Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
512 Some(Type::Optional(opt)) => match &*opt.inner {
513 Type::Array(array_ty) => Some(array_ty.element_type().clone()),
514 _ => None,
515 },
516 _ => None,
517 };
518
519 let inferred_type = if input.elements.is_empty() {
520 if let Some(ty) = element_type.clone() {
521 ty
522 } else {
523 self.emit_err(TypeCheckerError::could_not_determine_type(input, input.span()));
524 Type::Err
525 }
526 } else {
527 self.visit_expression_reject_numeric(&input.elements[0], &element_type)
528 };
529
530 if input.elements.len() > self.limits.max_array_elements {
531 self.emit_err(TypeCheckerError::array_too_large(
532 input.elements.len(),
533 self.limits.max_array_elements,
534 input.span(),
535 ));
536 }
537
538 for expression in input.elements.iter().skip(1) {
539 let next_type = self.visit_expression_reject_numeric(expression, &element_type);
540
541 if next_type == Type::Err {
542 return Type::Err;
543 }
544
545 if let Some(ref element_type) = element_type {
546 self.assert_type(&next_type, element_type, expression.span());
547 } else {
548 self.assert_type(&next_type, &inferred_type, expression.span());
549 }
550 }
551
552 if inferred_type == Type::Err {
553 return Type::Err;
554 }
555
556 let type_ = Type::Array(ArrayType::new(
557 inferred_type,
558 Expression::Literal(Literal {
559 variant: LiteralVariant::Integer(IntegerType::U32, input.elements.len().to_string()),
561 id: self.state.node_builder.next_id(),
562 span: Span::default(),
563 }),
564 ));
565
566 self.maybe_assert_type(&type_, additional, input.span());
567
568 type_
569 }
570
571 fn visit_repeat(&mut self, input: &RepeatExpression, additional: &Self::AdditionalInput) -> Self::Output {
572 let expected_element_type = match additional {
575 Some(Type::Array(array_ty)) => Some(array_ty.element_type().clone()),
576 Some(Type::Optional(opt)) => match &*opt.inner {
577 Type::Array(array_ty) => Some(array_ty.element_type().clone()),
578 _ => None,
579 },
580 _ => None,
581 };
582
583 let inferred_element_type = self.visit_expression_reject_numeric(&input.expr, &expected_element_type);
584
585 self.visit_expression_infer_default_u32(&input.count);
588
589 if let Some(count) = input.count.as_u32()
592 && count > self.limits.max_array_elements as u32
593 {
594 self.emit_err(TypeCheckerError::array_too_large(count, self.limits.max_array_elements, input.span()));
595 }
596
597 let type_ = Type::Array(ArrayType::new(inferred_element_type, input.count.clone()));
598
599 self.maybe_assert_type(&type_, additional, input.span());
600 type_
601 }
602
603 fn visit_associated_constant(
604 &mut self,
605 input: &AssociatedConstantExpression,
606 expected: &Self::AdditionalInput,
607 ) -> Self::Output {
608 let Some(core_constant) = self.get_core_constant(&input.ty, &input.name) else {
610 self.emit_err(TypeCheckerError::invalid_associated_constant(input, input.span));
611 return Type::Err;
612 };
613 let type_ = core_constant.to_type();
614 self.maybe_assert_type(&type_, expected, input.span());
615 type_
616 }
617
618 fn visit_associated_function(
619 &mut self,
620 input: &AssociatedFunctionExpression,
621 expected: &Self::AdditionalInput,
622 ) -> Self::Output {
623 let Some(core_instruction) = self.get_core_function_call(input) else {
625 self.emit_err(TypeCheckerError::invalid_core_function_call(input, input.span()));
626 return Type::Err;
627 };
628 if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Script))
630 && self.async_block_id.is_none()
631 && core_instruction.is_finalize_command()
632 {
633 self.emit_err(TypeCheckerError::operation_must_be_in_async_block_or_function(input.span()));
634 }
635
636 let return_type =
637 self.check_core_function_call(core_instruction.clone(), &input.arguments, expected, input.span());
638
639 self.maybe_assert_type(&return_type, expected, input.span());
641
642 if core_instruction == CoreFunction::FutureAwait && input.arguments.len() != 1 {
644 self.emit_err(TypeCheckerError::can_only_await_one_future_at_a_time(input.span));
645 }
646
647 return_type
648 }
649
650 fn visit_async(&mut self, input: &AsyncExpression, _additional: &Self::AdditionalInput) -> Self::Output {
651 self.async_block_id = Some(input.block.id);
653
654 if self.scope_state.is_conditional {
656 self.emit_err(TypeCheckerError::async_block_in_conditional(input.span));
657 }
658
659 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
660 self.emit_err(TypeCheckerError::illegal_async_block_location(input.span));
661 }
662
663 if self.scope_state.already_contains_an_async_block {
664 self.emit_err(TypeCheckerError::multiple_async_blocks_not_allowed(input.span));
665 }
666
667 if self.scope_state.has_called_finalize {
668 self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
669 }
670
671 self.visit_block(&input.block);
672
673 self.scope_state.already_contains_an_async_block = true;
675
676 self.async_block_id = None;
678
679 Type::Future(FutureType::new(Vec::new(), None, false))
682 }
683
684 fn visit_binary(&mut self, input: &BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
685 let assert_same_type = |slf: &Self, t1: &Type, t2: &Type| -> Type {
686 if t1 == &Type::Err || t2 == &Type::Err {
687 Type::Err
688 } else if !t1.eq_user(t2) {
689 slf.emit_err(TypeCheckerError::operation_types_mismatch(input.op, t1, t2, input.span()));
690 Type::Err
691 } else {
692 t1.clone()
693 }
694 };
695
696 let infer_numeric_types = |slf: &Self, left_type: &mut Type, right_type: &mut Type| {
704 use Type::*;
705
706 match (&*left_type, &*right_type) {
707 (Numeric, Numeric) => {
709 slf.emit_inference_failure_error(left_type, &input.left);
710 slf.emit_inference_failure_error(right_type, &input.right);
711 }
712
713 (Numeric, Err) => slf.emit_inference_failure_error(left_type, &input.left),
715
716 (Err, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
718
719 (Integer(_) | Field | Group | Scalar, Numeric) => {
721 *right_type = left_type.clone();
722 slf.state.type_table.insert(input.right.id(), right_type.clone());
723 if let Expression::Literal(literal) = &input.right {
724 slf.check_numeric_literal(literal, right_type);
725 }
726 }
727
728 (Numeric, Integer(_) | Field | Group | Scalar) => {
730 *left_type = right_type.clone();
731 slf.state.type_table.insert(input.left.id(), left_type.clone());
732 if let Expression::Literal(literal) = &input.left {
733 slf.check_numeric_literal(literal, left_type);
734 }
735 }
736
737 (Numeric, _) => slf.emit_inference_failure_error(left_type, &input.left),
739
740 (_, Numeric) => slf.emit_inference_failure_error(right_type, &input.right),
742
743 _ => {}
745 }
746 };
747
748 match input.op {
749 BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
750 self.maybe_assert_type(&Type::Boolean, destination, input.span());
751 self.visit_expression(&input.left, &Some(Type::Boolean));
752 self.visit_expression(&input.right, &Some(Type::Boolean));
753 Type::Boolean
754 }
755 BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
756 let operand_expected = self.unwrap_optional_type(destination);
757
758 let mut t1 = self.visit_expression(&input.left, &operand_expected);
760 let mut t2 = self.visit_expression(&input.right, &operand_expected);
761
762 infer_numeric_types(self, &mut t1, &mut t2);
764
765 self.assert_bool_int_type(&t1, input.left.span());
767 self.assert_bool_int_type(&t2, input.right.span());
768
769 let result_t = assert_same_type(self, &t1, &t2);
770 self.maybe_assert_type(&result_t, destination, input.span());
771
772 self.wrap_if_optional(result_t, destination)
773 }
774 BinaryOperation::Add => {
775 let operand_expected = self.unwrap_optional_type(destination);
776
777 let mut t1 = self.visit_expression(&input.left, &operand_expected);
779 let mut t2 = self.visit_expression(&input.right, &operand_expected);
780
781 infer_numeric_types(self, &mut t1, &mut t2);
783
784 let assert_add_type = |type_: &Type, span: Span| {
786 if !matches!(type_, Type::Err | Type::Field | Type::Group | Type::Scalar | Type::Integer(_)) {
787 self.emit_err(TypeCheckerError::type_should_be2(
788 type_,
789 "a field, group, scalar, or integer",
790 span,
791 ));
792 }
793 };
794
795 assert_add_type(&t1, input.left.span());
796 assert_add_type(&t2, input.right.span());
797
798 let result_t = assert_same_type(self, &t1, &t2);
799
800 self.maybe_assert_type(&result_t, destination, input.span());
801
802 self.wrap_if_optional(result_t, destination)
803 }
804 BinaryOperation::Sub => {
805 let operand_expected = self.unwrap_optional_type(destination);
806
807 let mut t1 = self.visit_expression(&input.left, &operand_expected);
809 let mut t2 = self.visit_expression(&input.right, &operand_expected);
810
811 infer_numeric_types(self, &mut t1, &mut t2);
813
814 self.assert_field_group_int_type(&t1, input.left.span());
816 self.assert_field_group_int_type(&t2, input.right.span());
817
818 let result_t = assert_same_type(self, &t1, &t2);
819
820 self.maybe_assert_type(&result_t, destination, input.span());
821
822 self.wrap_if_optional(result_t, destination)
823 }
824 BinaryOperation::Mul => {
825 let unwrapped_dest = self.unwrap_optional_type(destination);
826
827 let expected = if matches!(unwrapped_dest, Some(Type::Group)) { &None } else { &unwrapped_dest };
831 let mut t1 = self.visit_expression(&input.left, expected);
832 let mut t2 = self.visit_expression(&input.right, expected);
833
834 match (&t1, &t2) {
840 (Type::Group, Type::Numeric) => infer_numeric_types(self, &mut Type::Scalar, &mut t2),
841 (Type::Numeric, Type::Group) => infer_numeric_types(self, &mut t1, &mut Type::Scalar),
842 (Type::Scalar, Type::Numeric) => infer_numeric_types(self, &mut Type::Group, &mut t2),
843 (Type::Numeric, Type::Scalar) => infer_numeric_types(self, &mut t1, &mut Type::Group),
844 (_, _) => infer_numeric_types(self, &mut t1, &mut t2),
845 }
846
847 let result_t = match (&t1, &t2) {
849 (Type::Err, _) | (_, Type::Err) => Type::Err,
850 (Type::Group, Type::Scalar) | (Type::Scalar, Type::Group) => Type::Group,
851 (Type::Field, Type::Field) => Type::Field,
852 (Type::Integer(integer_type1), Type::Integer(integer_type2)) if integer_type1 == integer_type2 => {
853 t1.clone()
854 }
855 _ => {
856 self.emit_err(TypeCheckerError::mul_types_mismatch(t1, t2, input.span()));
857 Type::Err
858 }
859 };
860
861 self.maybe_assert_type(&result_t, destination, input.span());
862
863 self.wrap_if_optional(result_t, destination)
864 }
865 BinaryOperation::Div => {
866 let operand_expected = self.unwrap_optional_type(destination);
867
868 let mut t1 = self.visit_expression(&input.left, &operand_expected);
870 let mut t2 = self.visit_expression(&input.right, &operand_expected);
871
872 infer_numeric_types(self, &mut t1, &mut t2);
874
875 self.assert_field_int_type(&t1, input.left.span());
877 self.assert_field_int_type(&t2, input.right.span());
878
879 let result_t = assert_same_type(self, &t1, &t2);
880
881 self.maybe_assert_type(&result_t, destination, input.span());
882
883 self.wrap_if_optional(result_t, destination)
884 }
885 BinaryOperation::Rem | BinaryOperation::RemWrapped => {
886 let operand_expected = self.unwrap_optional_type(destination);
887
888 let mut t1 = self.visit_expression(&input.left, &operand_expected);
890 let mut t2 = self.visit_expression(&input.right, &operand_expected);
891
892 infer_numeric_types(self, &mut t1, &mut t2);
894
895 self.assert_int_type(&t1, input.left.span());
897 self.assert_int_type(&t2, input.right.span());
898
899 let result_t = assert_same_type(self, &t1, &t2);
900
901 self.maybe_assert_type(&result_t, destination, input.span());
902
903 self.wrap_if_optional(result_t, destination)
904 }
905 BinaryOperation::Mod => {
906 let operand_expected = self.unwrap_optional_type(destination);
907
908 let mut t1 = self.visit_expression(&input.left, &operand_expected);
910 let mut t2 = self.visit_expression(&input.right, &operand_expected);
911
912 infer_numeric_types(self, &mut t1, &mut t2);
914
915 self.assert_unsigned_type(&t1, input.left.span());
917 self.assert_unsigned_type(&t2, input.right.span());
918
919 let result_t = assert_same_type(self, &t1, &t2);
920
921 self.maybe_assert_type(&result_t, destination, input.span());
922
923 self.wrap_if_optional(result_t, destination)
924 }
925 BinaryOperation::Pow => {
926 let operand_expected = self.unwrap_optional_type(destination);
927
928 let mut t1 = self.visit_expression(&input.left, &operand_expected);
930
931 let mut t2 = self.visit_expression(&input.right, &None);
933
934 if matches!((&t1, &t2), (Type::Field, Type::Numeric) | (Type::Numeric, Type::Field)) {
937 infer_numeric_types(self, &mut t1, &mut t2);
938 } else {
939 if matches!(t1, Type::Numeric) {
940 self.emit_inference_failure_error(&mut t1, &input.left);
941 }
942 if matches!(t2, Type::Numeric) {
943 self.emit_inference_failure_error(&mut t2, &input.right);
944 }
945 }
946
947 let ty = match (&t1, &t2) {
949 (Type::Err, _) | (_, Type::Err) => Type::Err,
950 (Type::Field, Type::Field) => Type::Field,
951 (base @ Type::Integer(_), t2) => {
952 if !matches!(
953 t2,
954 Type::Integer(IntegerType::U8)
955 | Type::Integer(IntegerType::U16)
956 | Type::Integer(IntegerType::U32)
957 ) {
958 self.emit_err(TypeCheckerError::pow_types_mismatch(base, t2, input.span()));
959 }
960 base.clone()
961 }
962 _ => {
963 self.emit_err(TypeCheckerError::pow_types_mismatch(t1, t2, input.span()));
964 Type::Err
965 }
966 };
967
968 self.maybe_assert_type(&ty, destination, input.span());
969
970 self.wrap_if_optional(ty, destination)
971 }
972 BinaryOperation::Eq | BinaryOperation::Neq => {
973 let (mut t1, mut t2) =
983 if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.right {
984 let t1 = self.visit_expression(&input.left, &None);
985 (t1.clone(), self.visit_expression(&input.right, &Some(t1.clone())))
986 } else if let Expression::Literal(Literal { variant: LiteralVariant::None, .. }) = input.left {
987 let t2 = self.visit_expression(&input.right, &None);
988 (self.visit_expression(&input.left, &Some(t2.clone())), t2)
989 } else {
990 (self.visit_expression(&input.left, &None), self.visit_expression(&input.right, &None))
991 };
992
993 infer_numeric_types(self, &mut t1, &mut t2);
995
996 let _ = assert_same_type(self, &t1, &t2);
998
999 self.maybe_assert_type(&Type::Boolean, destination, input.span());
1000
1001 Type::Boolean
1002 }
1003 BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Lte | BinaryOperation::Gte => {
1004 let mut t1 = self.visit_expression(&input.left, &None);
1006 let mut t2 = self.visit_expression(&input.right, &None);
1007
1008 infer_numeric_types(self, &mut t1, &mut t2);
1010
1011 let assert_compare_type = |type_: &Type, span: Span| {
1013 if !matches!(type_, Type::Err | Type::Field | Type::Scalar | Type::Integer(_)) {
1014 self.emit_err(TypeCheckerError::type_should_be2(type_, "a field, scalar, or integer", span));
1015 }
1016 };
1017
1018 assert_compare_type(&t1, input.left.span());
1019 assert_compare_type(&t2, input.right.span());
1020
1021 let _ = assert_same_type(self, &t1, &t2);
1022
1023 self.maybe_assert_type(&Type::Boolean, destination, input.span());
1024
1025 Type::Boolean
1026 }
1027 BinaryOperation::AddWrapped
1028 | BinaryOperation::SubWrapped
1029 | BinaryOperation::DivWrapped
1030 | BinaryOperation::MulWrapped => {
1031 let operand_expected = self.unwrap_optional_type(destination);
1032
1033 let mut t1 = self.visit_expression(&input.left, &operand_expected);
1035 let mut t2 = self.visit_expression(&input.right, &operand_expected);
1036
1037 infer_numeric_types(self, &mut t1, &mut t2);
1039
1040 self.assert_int_type(&t1, input.left.span());
1042 self.assert_int_type(&t2, input.right.span());
1043
1044 let result_t = assert_same_type(self, &t1, &t2);
1045
1046 self.maybe_assert_type(&result_t, destination, input.span());
1047
1048 self.wrap_if_optional(result_t, destination)
1049 }
1050 BinaryOperation::Shl
1051 | BinaryOperation::ShlWrapped
1052 | BinaryOperation::Shr
1053 | BinaryOperation::ShrWrapped
1054 | BinaryOperation::PowWrapped => {
1055 let operand_expected = self.unwrap_optional_type(destination);
1056
1057 let t1 = self.visit_expression_reject_numeric(&input.left, &operand_expected);
1059
1060 let t2 = self.visit_expression_reject_numeric(&input.right, &None);
1062
1063 self.assert_int_type(&t1, input.left.span());
1064
1065 if !matches!(
1066 &t2,
1067 Type::Err
1068 | Type::Integer(IntegerType::U8)
1069 | Type::Integer(IntegerType::U16)
1070 | Type::Integer(IntegerType::U32)
1071 ) {
1072 self.emit_err(TypeCheckerError::shift_type_magnitude(input.op, t2, input.right.span()));
1073 }
1074
1075 self.wrap_if_optional(t1, destination)
1076 }
1077 }
1078 }
1079
1080 fn visit_call(&mut self, input: &CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
1081 let callee_program = input.program.or(self.scope_state.program_name).unwrap();
1082
1083 let callee_path = input.function.absolute_path();
1084
1085 let Some(func_symbol) =
1086 self.state.symbol_table.lookup_function(&Location::new(callee_program, callee_path.clone()))
1087 else {
1088 self.emit_err(TypeCheckerError::unknown_sym("function", input.function.clone(), input.function.span()));
1089 return Type::Err;
1090 };
1091
1092 let func = func_symbol.function.clone();
1093
1094 match self.scope_state.variant.unwrap() {
1097 Variant::AsyncFunction | Variant::Function if !matches!(func.variant, Variant::Inline) => self.emit_err(
1098 TypeCheckerError::can_only_call_inline_function("a `function`, `inline`, or `constructor`", input.span),
1099 ),
1100 Variant::Transition | Variant::AsyncTransition
1101 if matches!(func.variant, Variant::Transition)
1102 && input.program.is_none_or(|program| program == self.scope_state.program_name.unwrap()) =>
1103 {
1104 self.emit_err(TypeCheckerError::cannot_invoke_call_to_local_transition_function(input.span))
1105 }
1106 _ => {}
1107 }
1108
1109 if func.variant == Variant::Inline
1111 && input.program.is_some_and(|program| program != self.scope_state.program_name.unwrap())
1112 {
1113 self.emit_err(TypeCheckerError::cannot_call_external_inline_function(input.span));
1114 }
1115
1116 if self.async_block_id.is_some() && !matches!(func.variant, Variant::Inline) {
1118 self.emit_err(TypeCheckerError::can_only_call_inline_function("an async block", input.span));
1119 }
1120
1121 let mut ret = if func.variant == Variant::AsyncFunction {
1123 Type::Future(FutureType::new(
1125 Vec::new(),
1126 Some(Location::new(callee_program, input.function.absolute_path())),
1127 false,
1128 ))
1129 } else if func.variant == Variant::AsyncTransition {
1130 let Some(inputs) =
1132 self.async_function_input_types.get(&Location::new(callee_program, vec![Symbol::intern(&format!(
1133 "finalize/{}",
1134 input.function.identifier().name
1135 ))]))
1136 else {
1137 self.emit_err(TypeCheckerError::async_function_not_found(input.function.clone(), input.span));
1138 return Type::Future(FutureType::new(
1139 Vec::new(),
1140 Some(Location::new(callee_program, callee_path.clone())),
1141 false,
1142 ));
1143 };
1144
1145 let future_type = Type::Future(FutureType::new(
1146 inputs.clone(),
1147 Some(Location::new(callee_program, callee_path.clone())),
1148 true,
1149 ));
1150 let fully_inferred_type = match &func.output_type {
1151 Type::Tuple(tup) => Type::Tuple(TupleType::new(
1152 tup.elements()
1153 .iter()
1154 .map(|t| if matches!(t, Type::Future(_)) { future_type.clone() } else { t.clone() })
1155 .collect::<Vec<Type>>(),
1156 )),
1157 Type::Future(_) => future_type,
1158 _ => panic!("Invalid output type for async transition."),
1159 };
1160 self.assert_and_return_type(fully_inferred_type, expected, input.span())
1161 } else {
1162 self.assert_and_return_type(func.output_type, expected, input.span())
1163 };
1164
1165 if func.input.len() != input.arguments.len() {
1167 self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
1168 func.input.len(),
1169 input.arguments.len(),
1170 input.span(),
1171 ));
1172 }
1173
1174 if func.const_parameters.len() != input.const_arguments.len() {
1176 self.emit_err(TypeCheckerError::incorrect_num_const_args(
1177 "Call",
1178 func.const_parameters.len(),
1179 input.const_arguments.len(),
1180 input.span(),
1181 ));
1182 }
1183
1184 for (expected, argument) in func.const_parameters.iter().zip(input.const_arguments.iter()) {
1186 self.visit_expression(argument, &Some(expected.type_().clone()));
1187 }
1188
1189 let (mut input_futures, mut inferred_finalize_inputs) = (Vec::new(), Vec::new());
1190 for (expected, argument) in func.input.iter().zip(input.arguments.iter()) {
1191 let ty = self.visit_expression(argument, &Some(expected.type_().clone()));
1193
1194 if ty == Type::Err {
1195 return Type::Err;
1196 }
1197 if func.variant == Variant::AsyncFunction && matches!(expected.type_(), Type::Future(_)) {
1199 let option_name = match argument {
1201 Expression::Path(path) => Some(path.identifier().name),
1202 Expression::TupleAccess(tuple_access) => {
1203 if let Expression::Path(path) = &tuple_access.tuple {
1204 Some(path.identifier().name)
1205 } else {
1206 None
1207 }
1208 }
1209 _ => None,
1210 };
1211
1212 if let Some(name) = option_name {
1213 match self.scope_state.futures.shift_remove(&name) {
1214 Some(future) => {
1215 self.scope_state.call_location = Some(future);
1216 }
1217 None => {
1218 self.emit_err(TypeCheckerError::unknown_future_consumed(name, argument.span()));
1219 }
1220 }
1221 }
1222
1223 match argument {
1224 Expression::Path(_) | Expression::Call(_) | Expression::TupleAccess(_) => {
1225 match &self.scope_state.call_location {
1226 Some(location) => {
1227 input_futures.push(location.clone());
1229 inferred_finalize_inputs.push(ty);
1231 }
1232 None => {
1233 self.emit_err(TypeCheckerError::unknown_future_consumed(argument, argument.span()));
1234 }
1235 }
1236 }
1237 _ => {
1238 self.emit_err(TypeCheckerError::unknown_future_consumed("unknown", argument.span()));
1239 }
1240 }
1241 } else {
1242 inferred_finalize_inputs.push(ty);
1243 }
1244 }
1245
1246 let caller_program =
1247 self.scope_state.program_name.expect("`program_name` is always set before traversing a program scope");
1248 let caller_function = if self.scope_state.is_constructor {
1251 sym::constructor
1252 } else {
1253 self.scope_state.function.expect("`function` is always set before traversing a function scope")
1254 };
1255
1256 let caller_path = self
1258 .scope_state
1259 .module_name
1260 .iter()
1261 .cloned()
1262 .chain(std::iter::once(caller_function))
1263 .collect::<Vec<Symbol>>();
1264
1265 let caller = Location::new(caller_program, caller_path.clone());
1266 let callee = Location::new(callee_program, callee_path.clone());
1267 self.state.call_graph.add_edge(caller, callee);
1268
1269 if func.variant.is_transition() && self.scope_state.variant == Some(Variant::AsyncTransition) {
1270 if self.scope_state.has_called_finalize {
1271 self.emit_err(TypeCheckerError::external_call_after_async("function call", input.span));
1272 }
1273
1274 if self.scope_state.already_contains_an_async_block {
1275 self.emit_err(TypeCheckerError::external_call_after_async("block", input.span));
1276 }
1277 }
1278
1279 if func.variant.is_async_function() {
1281 if self.scope_state.is_conditional {
1283 self.emit_err(TypeCheckerError::async_call_in_conditional(input.span));
1284 }
1285
1286 if !matches!(self.scope_state.variant, Some(Variant::AsyncTransition) | Some(Variant::Script)) {
1288 self.emit_err(TypeCheckerError::async_call_can_only_be_done_from_async_transition(input.span));
1289 }
1290
1291 if self.scope_state.has_called_finalize {
1293 self.emit_err(TypeCheckerError::must_call_async_function_once(input.span));
1294 }
1295
1296 if self.scope_state.already_contains_an_async_block {
1297 self.emit_err(TypeCheckerError::conflicting_async_call_and_block(input.span));
1298 }
1299
1300 if !self.scope_state.futures.is_empty() {
1302 self.emit_err(TypeCheckerError::not_all_futures_consumed(
1303 self.scope_state.futures.iter().map(|(f, _)| f).join(", "),
1304 input.span,
1305 ));
1306 }
1307 self.state
1308 .symbol_table
1309 .attach_finalizer(
1310 Location::new(callee_program, caller_path),
1311 Location::new(callee_program, callee_path.clone()),
1312 input_futures,
1313 inferred_finalize_inputs.clone(),
1314 )
1315 .expect("Failed to attach finalizer");
1316 self.async_function_callers
1318 .entry(Location::new(self.scope_state.program_name.unwrap(), callee_path.clone()))
1319 .or_default()
1320 .insert(self.scope_state.location());
1321
1322 self.scope_state.has_called_finalize = true;
1324
1325 ret = Type::Future(FutureType::new(
1327 inferred_finalize_inputs,
1328 Some(Location::new(callee_program, callee_path.clone())),
1329 true,
1330 ));
1331
1332 self.assert_and_return_type(ret.clone(), expected, input.span());
1334 }
1335
1336 self.scope_state.call_location = Some(Location::new(callee_program, callee_path.clone()));
1338
1339 ret
1340 }
1341
1342 fn visit_cast(&mut self, input: &CastExpression, expected: &Self::AdditionalInput) -> Self::Output {
1343 let expression_type = self.visit_expression_reject_numeric(&input.expression, &None);
1344
1345 let assert_castable_type = |actual: &Type, span: Span| {
1346 if !matches!(
1347 actual,
1348 Type::Integer(_) | Type::Boolean | Type::Field | Type::Group | Type::Scalar | Type::Address | Type::Err,
1349 ) {
1350 self.emit_err(TypeCheckerError::type_should_be2(
1351 actual,
1352 "an integer, bool, field, group, scalar, or address",
1353 span,
1354 ));
1355 }
1356 };
1357
1358 assert_castable_type(&input.type_, input.span());
1359
1360 assert_castable_type(&expression_type, input.expression.span());
1361
1362 self.maybe_assert_type(&input.type_, expected, input.span());
1363
1364 input.type_.clone()
1365 }
1366
1367 fn visit_struct_init(&mut self, input: &StructExpression, additional: &Self::AdditionalInput) -> Self::Output {
1368 let struct_ = self.lookup_struct(self.scope_state.program_name, &input.path.absolute_path()).clone();
1369 let Some(struct_) = struct_ else {
1370 self.emit_err(TypeCheckerError::unknown_sym("struct or record", input.path.clone(), input.path.span()));
1371 return Type::Err;
1372 };
1373
1374 if struct_.const_parameters.len() != input.const_arguments.len() {
1376 self.emit_err(TypeCheckerError::incorrect_num_const_args(
1377 "Struct expression",
1378 struct_.const_parameters.len(),
1379 input.const_arguments.len(),
1380 input.span(),
1381 ));
1382 }
1383
1384 for (expected, argument) in struct_.const_parameters.iter().zip(input.const_arguments.iter()) {
1386 self.visit_expression(argument, &Some(expected.type_().clone()));
1387 }
1388
1389 let type_ = Type::Composite(CompositeType {
1392 path: input.path.clone(),
1393 const_arguments: input.const_arguments.clone(),
1394 program: None,
1395 });
1396 self.maybe_assert_type(&type_, additional, input.path.span());
1397
1398 if struct_.members.len() != input.members.len() {
1400 self.emit_err(TypeCheckerError::incorrect_num_struct_members(
1401 struct_.members.len(),
1402 input.members.len(),
1403 input.span(),
1404 ));
1405 }
1406
1407 for Member { identifier, type_, .. } in struct_.members.iter() {
1408 if let Some(actual) = input.members.iter().find(|member| member.identifier.name == identifier.name) {
1409 match &actual.expression {
1410 None => {
1411 self.visit_expression(
1415 &Path::from(actual.identifier)
1416 .with_absolute_path(Some(
1417 self.scope_state
1418 .module_name
1419 .iter()
1420 .cloned()
1421 .chain(std::iter::once(actual.identifier.name))
1422 .collect::<Vec<Symbol>>(),
1423 ))
1424 .into(),
1425 &Some(type_.clone()),
1426 );
1427 }
1428 Some(expr) => {
1429 self.visit_expression(expr, &Some(type_.clone()));
1431 }
1432 };
1433 } else {
1434 self.emit_err(TypeCheckerError::missing_struct_member(struct_.identifier, identifier, input.span()));
1435 };
1436 }
1437
1438 if struct_.is_record {
1439 if self.scope_state.variant == Some(Variant::AsyncFunction) {
1442 self.state
1443 .handler
1444 .emit_err(TypeCheckerError::records_not_allowed_inside_async("function", input.span()));
1445 }
1446
1447 if self.async_block_id.is_some() {
1450 self.state.handler.emit_err(TypeCheckerError::records_not_allowed_inside_async("block", input.span()));
1451 }
1452
1453 input.members.iter().filter(|init| init.identifier.name == sym::owner).for_each(|init| {
1458 if let Some(Expression::MemberAccess(access)) = &init.expression
1459 && let MemberAccess {
1460 inner: Expression::Path(path),
1461 name: Identifier { name: sym::caller, .. },
1462 ..
1463 } = &**access
1464 && path.identifier().name == sym::SelfLower
1465 {
1466 self.emit_warning(TypeCheckerWarning::caller_as_record_owner(input.path.clone(), access.span()));
1467 }
1468 });
1469 }
1470
1471 type_
1472 }
1473
1474 fn visit_err(&mut self, _input: &ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1476 Type::Err
1477 }
1478
1479 fn visit_path(&mut self, input: &Path, expected: &Self::AdditionalInput) -> Self::Output {
1480 let var = self.state.symbol_table.lookup_path(self.scope_state.program_name.unwrap(), &input.absolute_path());
1481
1482 if let Some(var) = var {
1483 if var.declaration == VariableType::Storage && !var.type_.is_vector() && !var.type_.is_mapping() {
1484 self.check_access_allowed("storage access", true, input.span());
1485 }
1486
1487 self.maybe_assert_type(&var.type_, expected, input.span());
1488 var.type_.clone()
1489 } else {
1490 self.emit_err(TypeCheckerError::unknown_sym("variable", input, input.span()));
1491 Type::Err
1492 }
1493 }
1494
1495 fn visit_literal(&mut self, input: &Literal, expected: &Self::AdditionalInput) -> Self::Output {
1496 let span = input.span();
1497
1498 macro_rules! parse_and_return {
1499 ($ty:ty, $variant:expr, $str:expr, $label:expr) => {{
1500 self.parse_integer_literal::<$ty>($str, span, $label);
1501 Type::Integer($variant)
1502 }};
1503 }
1504
1505 let type_ = match &input.variant {
1506 LiteralVariant::Address(..) => Type::Address,
1507 LiteralVariant::Boolean(..) => Type::Boolean,
1508 LiteralVariant::Field(..) => Type::Field,
1509 LiteralVariant::Scalar(..) => Type::Scalar,
1510 LiteralVariant::String(..) => Type::String,
1511 LiteralVariant::Integer(kind, string) => match kind {
1512 IntegerType::U8 => parse_and_return!(u8, IntegerType::U8, string, "u8"),
1513 IntegerType::U16 => parse_and_return!(u16, IntegerType::U16, string, "u16"),
1514 IntegerType::U32 => parse_and_return!(u32, IntegerType::U32, string, "u32"),
1515 IntegerType::U64 => parse_and_return!(u64, IntegerType::U64, string, "u64"),
1516 IntegerType::U128 => parse_and_return!(u128, IntegerType::U128, string, "u128"),
1517 IntegerType::I8 => parse_and_return!(i8, IntegerType::I8, string, "i8"),
1518 IntegerType::I16 => parse_and_return!(i16, IntegerType::I16, string, "i16"),
1519 IntegerType::I32 => parse_and_return!(i32, IntegerType::I32, string, "i32"),
1520 IntegerType::I64 => parse_and_return!(i64, IntegerType::I64, string, "i64"),
1521 IntegerType::I128 => parse_and_return!(i128, IntegerType::I128, string, "i128"),
1522 },
1523 LiteralVariant::Group(s) => {
1524 let trimmed = s.trim_start_matches('-').trim_start_matches('0');
1525 if !trimmed.is_empty()
1526 && format!("{trimmed}group")
1527 .parse::<snarkvm::prelude::Group<snarkvm::prelude::TestnetV0>>()
1528 .is_err()
1529 {
1530 self.emit_err(TypeCheckerError::invalid_int_value(trimmed, "group", span));
1531 }
1532 Type::Group
1533 }
1534 LiteralVariant::Unsuffixed(_) => match expected {
1535 Some(ty @ Type::Integer(_) | ty @ Type::Field | ty @ Type::Group | ty @ Type::Scalar) => {
1536 self.check_numeric_literal(input, ty);
1537 ty.clone()
1538 }
1539 Some(ty @ Type::Optional(opt)) => {
1540 let inner = &opt.inner;
1542 match &**inner {
1543 Type::Integer(_) | Type::Field | Type::Group | Type::Scalar => {
1544 self.check_numeric_literal(input, inner);
1545 Type::Optional(OptionalType { inner: Box::new(*inner.clone()) })
1546 }
1547 _ => {
1548 self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(
1549 format!("type `{ty}`"),
1550 span,
1551 ));
1552 Type::Err
1553 }
1554 }
1555 }
1556 Some(ty) => {
1557 self.emit_err(TypeCheckerError::unexpected_unsuffixed_numeral(format!("type `{ty}`"), span));
1558 Type::Err
1559 }
1560 None => Type::Numeric,
1561 },
1562 LiteralVariant::None => {
1563 if let Some(ty @ Type::Optional(_)) = expected {
1564 ty.clone()
1565 } else if let Some(ty) = expected {
1566 self.emit_err(TypeCheckerError::none_found_non_optional(format!("{ty}"), span));
1567 Type::Err
1568 } else {
1569 self.emit_err(TypeCheckerError::could_not_determine_type(format!("{input}"), span));
1570 Type::Err
1571 }
1572 }
1573 };
1574
1575 self.maybe_assert_type(&type_, expected, span);
1576
1577 type_
1578 }
1579
1580 fn visit_locator(&mut self, input: &LocatorExpression, expected: &Self::AdditionalInput) -> Self::Output {
1581 let maybe_var =
1582 self.state.symbol_table.lookup_global(&Location::new(input.program.name.name, vec![input.name])).cloned();
1583 if let Some(var) = maybe_var {
1584 self.maybe_assert_type(&var.type_, expected, input.span());
1585 var.type_
1586 } else {
1587 self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));
1588 Type::Err
1589 }
1590 }
1591
1592 fn visit_ternary(&mut self, input: &TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
1593 self.visit_expression(&input.condition, &Some(Type::Boolean));
1594
1595 let (t1, t2) = if expected.is_some() {
1597 (
1598 self.visit_expression_reject_numeric(&input.if_true, expected),
1599 self.visit_expression_reject_numeric(&input.if_false, expected),
1600 )
1601 } else if input.if_false.is_none_expr() {
1602 let t1 = self.visit_expression(&input.if_true, &None);
1603 if matches!(t1, Type::Optional(_)) {
1604 (t1.clone(), self.visit_expression(&input.if_false, &Some(t1.clone())))
1605 } else {
1606 (
1607 t1.clone(),
1608 self.visit_expression(
1609 &input.if_false,
1610 &Some(Type::Optional(OptionalType { inner: Box::new(t1.clone()) })),
1611 ),
1612 )
1613 }
1614 } else if input.if_true.is_none_expr() {
1615 let t2 = self.visit_expression(&input.if_false, &None);
1616 if matches!(t2, Type::Optional(_)) {
1617 (t2.clone(), self.visit_expression(&input.if_true, &Some(t2.clone())))
1618 } else {
1619 (
1620 t2.clone(),
1621 self.visit_expression(
1622 &input.if_true,
1623 &Some(Type::Optional(OptionalType { inner: Box::new(t2.clone()) })),
1624 ),
1625 )
1626 }
1627 } else {
1628 (
1629 self.visit_expression_reject_numeric(&input.if_true, &None),
1630 self.visit_expression_reject_numeric(&input.if_false, &None),
1631 )
1632 };
1633
1634 let typ = if t1 == Type::Err || t2 == Type::Err {
1635 Type::Err
1636 } else if !t1.can_coerce_to(&t2) && !t2.can_coerce_to(&t1) {
1637 self.emit_err(TypeCheckerError::ternary_branch_mismatch(t1, t2, input.span()));
1638 Type::Err
1639 } else if let Some(expected) = expected {
1640 expected.clone()
1641 } else if t1.can_coerce_to(&t2) {
1642 t2
1643 } else {
1644 t1
1645 };
1646
1647 if self.is_external_record(&typ) {
1649 self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1650 }
1651
1652 if let Type::Tuple(tuple) = &typ
1654 && tuple.elements().iter().any(|ty| self.is_external_record(ty))
1655 {
1656 self.emit_err(TypeCheckerError::ternary_over_external_records(&typ, input.span));
1657 }
1658
1659 typ
1660 }
1661
1662 fn visit_tuple(&mut self, input: &TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
1663 if let Some(expected) = expected {
1664 if let Type::Tuple(expected_types) = expected {
1665 if expected_types.length() != input.elements.len() {
1669 self.emit_err(TypeCheckerError::incorrect_tuple_length(
1670 expected_types.length(),
1671 input.elements.len(),
1672 input.span(),
1673 ));
1674 }
1675
1676 input.elements.iter().zip(expected_types.elements()).for_each(|(expr, expected_el_ty)| {
1678 if matches!(expr, Expression::Tuple(_)) {
1679 self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1680 }
1681 self.visit_expression(expr, &Some(expected_el_ty.clone()));
1682 });
1683
1684 expected.clone()
1686 } else {
1687 let field_types = input
1691 .elements
1692 .iter()
1693 .map(|field| {
1694 let ty = self.visit_expression(field, &None);
1695 if ty == Type::Numeric {
1696 self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1697 Type::Err
1698 } else {
1699 ty
1700 }
1701 })
1702 .collect::<Vec<_>>();
1703 if field_types.iter().all(|f| *f != Type::Err) {
1704 let tuple_type = Type::Tuple(TupleType::new(field_types));
1705 self.emit_err(TypeCheckerError::type_should_be2(tuple_type, expected, input.span()));
1706 }
1707
1708 expected.clone()
1710 }
1711 } else {
1712 input.elements.iter().for_each(|expr| {
1716 if matches!(expr, Expression::Tuple(_)) {
1717 self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()));
1718 }
1719 });
1720
1721 Type::Tuple(TupleType::new(
1722 input
1723 .elements
1724 .iter()
1725 .map(|field| {
1726 let ty = self.visit_expression(field, &None);
1727 if ty == Type::Numeric {
1728 self.emit_err(TypeCheckerError::could_not_determine_type(field.clone(), field.span()));
1729 Type::Err
1730 } else {
1731 ty
1732 }
1733 })
1734 .collect::<Vec<_>>(),
1735 ))
1736 }
1737 }
1738
1739 fn visit_unary(&mut self, input: &UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
1740 let operand_expected = self.unwrap_optional_type(destination);
1741
1742 let assert_signed_int = |slf: &mut Self, type_: &Type| {
1743 if !matches!(
1744 type_,
1745 Type::Err
1746 | Type::Integer(IntegerType::I8)
1747 | Type::Integer(IntegerType::I16)
1748 | Type::Integer(IntegerType::I32)
1749 | Type::Integer(IntegerType::I64)
1750 | Type::Integer(IntegerType::I128)
1751 ) {
1752 slf.emit_err(TypeCheckerError::type_should_be2(type_, "a signed integer", input.span()));
1753 }
1754 };
1755
1756 let ty = match input.op {
1757 UnaryOperation::Abs => {
1758 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1759 assert_signed_int(self, &type_);
1760 type_
1761 }
1762 UnaryOperation::AbsWrapped => {
1763 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1764 assert_signed_int(self, &type_);
1765 type_
1766 }
1767 UnaryOperation::Double => {
1768 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1769 if !matches!(&type_, Type::Err | Type::Field | Type::Group) {
1770 self.emit_err(TypeCheckerError::type_should_be2(&type_, "a field or group", input.span()));
1771 }
1772 type_
1773 }
1774 UnaryOperation::Inverse => {
1775 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1776 if type_ == Type::Numeric {
1777 type_ = Type::Field;
1779 self.state.type_table.insert(input.receiver.id(), Type::Field);
1780 } else {
1781 self.assert_type(&type_, &Type::Field, input.span());
1782 }
1783 type_
1784 }
1785 UnaryOperation::Negate => {
1786 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1787 if !matches!(
1788 &type_,
1789 Type::Err
1790 | Type::Integer(IntegerType::I8)
1791 | Type::Integer(IntegerType::I16)
1792 | Type::Integer(IntegerType::I32)
1793 | Type::Integer(IntegerType::I64)
1794 | Type::Integer(IntegerType::I128)
1795 | Type::Group
1796 | Type::Field
1797 ) {
1798 self.emit_err(TypeCheckerError::type_should_be2(
1799 &type_,
1800 "a signed integer, group, or field",
1801 input.receiver.span(),
1802 ));
1803 }
1804 type_
1805 }
1806 UnaryOperation::Not => {
1807 let type_ = self.visit_expression_reject_numeric(&input.receiver, &operand_expected);
1808 if !matches!(&type_, Type::Err | Type::Boolean | Type::Integer(_)) {
1809 self.emit_err(TypeCheckerError::type_should_be2(&type_, "a bool or integer", input.span()));
1810 }
1811 type_
1812 }
1813 UnaryOperation::Square => {
1814 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1815 if type_ == Type::Numeric {
1816 type_ = Type::Field;
1818 self.state.type_table.insert(input.receiver.id(), Type::Field);
1819 } else {
1820 self.assert_type(&type_, &Type::Field, input.span());
1821 }
1822 type_
1823 }
1824 UnaryOperation::SquareRoot => {
1825 let mut type_ = self.visit_expression(&input.receiver, &operand_expected);
1826 if type_ == Type::Numeric {
1827 type_ = Type::Field;
1829 self.state.type_table.insert(input.receiver.id(), Type::Field);
1830 } else {
1831 self.assert_type(&type_, &Type::Field, input.span());
1832 }
1833 type_
1834 }
1835 UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
1836 let _operand_type = self.visit_expression(&input.receiver, &Some(Type::Group));
1837 self.maybe_assert_type(&Type::Field, destination, input.span());
1838 Type::Field
1839 }
1840 };
1841
1842 self.maybe_assert_type(&ty, destination, input.span());
1843
1844 self.wrap_if_optional(ty, destination)
1845 }
1846
1847 fn visit_unit(&mut self, _input: &UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output {
1848 Type::Unit
1849 }
1850
1851 fn visit_statement(&mut self, input: &Statement) {
1853 if self.scope_state.has_return {
1855 self.emit_err(TypeCheckerError::unreachable_code_after_return(input.span()));
1856 return;
1857 }
1858
1859 match input {
1860 Statement::Assert(stmt) => self.visit_assert(stmt),
1861 Statement::Assign(stmt) => self.visit_assign(stmt),
1862 Statement::Block(stmt) => self.visit_block(stmt),
1863 Statement::Conditional(stmt) => self.visit_conditional(stmt),
1864 Statement::Const(stmt) => self.visit_const(stmt),
1865 Statement::Definition(stmt) => self.visit_definition(stmt),
1866 Statement::Expression(stmt) => self.visit_expression_statement(stmt),
1867 Statement::Iteration(stmt) => self.visit_iteration(stmt),
1868 Statement::Return(stmt) => self.visit_return(stmt),
1869 }
1870 }
1871
1872 fn visit_assert(&mut self, input: &AssertStatement) {
1873 match &input.variant {
1874 AssertVariant::Assert(expr) => {
1875 let _type = self.visit_expression(expr, &Some(Type::Boolean));
1876 }
1877 AssertVariant::AssertEq(left, right) | AssertVariant::AssertNeq(left, right) => {
1878 let t1 = self.visit_expression_reject_numeric(left, &None);
1879 let t2 = self.visit_expression_reject_numeric(right, &None);
1880
1881 if t1 != Type::Err && t2 != Type::Err && !t1.eq_user(&t2) {
1882 let op =
1883 if matches!(input.variant, AssertVariant::AssertEq(..)) { "assert_eq" } else { "assert_neq" };
1884 self.emit_err(TypeCheckerError::operation_types_mismatch(op, t1, t2, input.span()));
1885 }
1886 }
1887 }
1888 }
1889
1890 fn visit_assign(&mut self, input: &AssignStatement) {
1891 let (lhs_type, is_storage) = self.visit_expression_assign(&input.place);
1892 let value = &input.value;
1893
1894 if lhs_type == Type::Err {
1895 self.visit_expression(value, &None);
1896 return;
1897 }
1898
1899 if is_storage && !lhs_type.is_vector() && !lhs_type.is_mapping() {
1900 self.check_access_allowed("storage write", true, input.place.span())
1901 }
1902
1903 let expected_rhs_ty = match (is_storage, value.is_none_expr(), &lhs_type) {
1904 (true, false, Type::Optional(OptionalType { inner })) => {
1905 Some(*inner.clone())
1921 }
1922 _ => {
1923 Some(lhs_type)
1925 }
1926 };
1927
1928 self.visit_expression(value, &expected_rhs_ty);
1929 }
1930
1931 fn visit_block(&mut self, input: &Block) {
1932 self.in_scope(input.id, |slf| {
1933 input.statements.iter().for_each(|stmt| slf.visit_statement(stmt));
1934 });
1935 }
1936
1937 fn visit_conditional(&mut self, input: &ConditionalStatement) {
1938 self.visit_expression(&input.condition, &Some(Type::Boolean));
1939
1940 let mut then_block_has_return = false;
1941 let mut otherwise_block_has_return = false;
1942
1943 let previous_has_return = core::mem::replace(&mut self.scope_state.has_return, then_block_has_return);
1945 let previous_is_conditional = core::mem::replace(&mut self.scope_state.is_conditional, true);
1947
1948 self.in_conditional_scope(|slf| slf.visit_block(&input.then));
1950
1951 then_block_has_return = self.scope_state.has_return;
1953
1954 if let Some(otherwise) = &input.otherwise {
1955 self.scope_state.has_return = otherwise_block_has_return;
1957
1958 match &**otherwise {
1959 Statement::Block(stmt) => {
1960 self.in_conditional_scope(|slf| slf.visit_block(stmt));
1962 }
1963 Statement::Conditional(stmt) => self.visit_conditional(stmt),
1964 _ => unreachable!("Else-case can only be a block or conditional statement."),
1965 }
1966
1967 otherwise_block_has_return = self.scope_state.has_return;
1969 }
1970
1971 self.scope_state.has_return = previous_has_return || (then_block_has_return && otherwise_block_has_return);
1973 self.scope_state.is_conditional = previous_is_conditional;
1975 }
1976
1977 fn visit_const(&mut self, input: &ConstDeclaration) {
1978 self.visit_type(&input.type_);
1979
1980 if self.contains_optional_type(&input.type_) {
1983 self.emit_err(TypeCheckerError::const_cannot_be_optional(input.span));
1984 }
1985
1986 match &input.type_ {
1988 Type::Unit => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.span)),
1990 Type::Tuple(tuple) => match tuple.length() {
1992 0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
1993 _ => {
1994 if tuple.elements().iter().any(|type_| matches!(type_, Type::Tuple(_))) {
1995 self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
1996 }
1997 }
1998 },
1999 Type::Mapping(_) | Type::Err => unreachable!(
2000 "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
2001 ),
2002 _ => (), }
2005
2006 self.visit_expression(&input.value, &Some(input.type_.clone()));
2008
2009 if self.scope_state.function.is_some() {
2010 if let Err(err) = self.state.symbol_table.insert_variable(
2013 self.scope_state.program_name.unwrap(),
2014 &[input.place.name],
2015 VariableSymbol { type_: input.type_.clone(), span: input.place.span, declaration: VariableType::Const },
2016 ) {
2017 self.state.handler.emit_err(err);
2018 }
2019 }
2020 }
2021
2022 fn visit_definition(&mut self, input: &DefinitionStatement) {
2023 if let Some(ty) = &input.type_ {
2025 self.visit_type(ty);
2026 self.assert_type_is_valid(ty, input.span);
2027 }
2028
2029 match &input.type_ {
2031 Some(Type::Tuple(tuple)) => match tuple.length() {
2033 0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
2034 _ => {
2035 for type_ in tuple.elements() {
2036 if matches!(type_, Type::Tuple(_)) {
2037 self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
2038 }
2039 }
2040 }
2041 },
2042 Some(Type::Mapping(_)) | Some(Type::Err) => unreachable!(
2043 "Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
2044 ),
2045 _ => (), }
2048
2049 let inferred_type = self.visit_expression_reject_numeric(&input.value, &input.type_);
2053
2054 if inferred_type.is_vector() {
2057 self.emit_err(TypeCheckerError::storage_vectors_cannot_be_moved_or_assigned(input.value.span()));
2058 }
2059
2060 match &input.place {
2062 DefinitionPlace::Single(identifier) => {
2063 self.insert_variable(
2064 Some(inferred_type.clone()),
2065 identifier,
2066 input.type_.clone().unwrap_or(inferred_type),
2068 identifier.span,
2069 );
2070 }
2071 DefinitionPlace::Multiple(identifiers) => {
2072 let tuple_type = match (&input.type_, inferred_type.clone()) {
2074 (Some(Type::Tuple(tuple_type)), _) => tuple_type.clone(),
2075 (None, Type::Tuple(tuple_type)) => tuple_type.clone(),
2076 _ => {
2077 return;
2079 }
2080 };
2081
2082 if identifiers.len() != tuple_type.length() {
2085 return self.emit_err(TypeCheckerError::incorrect_num_tuple_elements(
2086 identifiers.len(),
2087 tuple_type.length(),
2088 input.span(),
2089 ));
2090 }
2091
2092 for (i, identifier) in identifiers.iter().enumerate() {
2094 let inferred = if let Type::Tuple(inferred_tuple) = &inferred_type {
2095 inferred_tuple.elements().get(i).cloned().unwrap_or_default()
2096 } else {
2097 Type::Err
2098 };
2099 self.insert_variable(Some(inferred), identifier, tuple_type.elements()[i].clone(), identifier.span);
2100 }
2101 }
2102 }
2103 }
2104
2105 fn visit_expression_statement(&mut self, input: &ExpressionStatement) {
2106 if !matches!(input.expression, Expression::Call(_) | Expression::AssociatedFunction(_) | Expression::Unit(_)) {
2108 self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
2109 } else {
2110 self.visit_expression(&input.expression, &None);
2112 }
2113 }
2114
2115 fn visit_iteration(&mut self, input: &IterationStatement) {
2116 if let Some(ty) = &input.type_ {
2118 self.visit_type(ty);
2119 self.assert_int_type(ty, input.variable.span);
2120 }
2121
2122 let start_ty = self.visit_expression(&input.start, &input.type_.clone());
2125 let stop_ty = self.visit_expression(&input.stop, &input.type_.clone());
2126
2127 self.assert_int_type(&start_ty, input.start.span());
2129 self.assert_int_type(&stop_ty, input.stop.span());
2130
2131 if start_ty != stop_ty {
2132 self.emit_err(TypeCheckerError::range_bounds_type_mismatch(input.start.span() + input.stop.span()));
2134 }
2135
2136 let iterator_ty = input.type_.clone().unwrap_or(start_ty);
2140 self.state.type_table.insert(input.variable.id(), iterator_ty.clone());
2141
2142 self.in_scope(input.id(), |slf| {
2143 if let Err(err) = slf.state.symbol_table.insert_variable(
2145 slf.scope_state.program_name.unwrap(),
2146 &[input.variable.name],
2147 VariableSymbol { type_: iterator_ty.clone(), span: input.span(), declaration: VariableType::Const },
2148 ) {
2149 slf.state.handler.emit_err(err);
2150 }
2151
2152 let prior_has_return = core::mem::take(&mut slf.scope_state.has_return);
2153 let prior_has_finalize = core::mem::take(&mut slf.scope_state.has_called_finalize);
2154
2155 slf.visit_block(&input.block);
2156
2157 if slf.scope_state.has_return {
2158 slf.emit_err(TypeCheckerError::loop_body_contains_return(input.span()));
2159 }
2160
2161 if slf.scope_state.has_called_finalize {
2162 slf.emit_err(TypeCheckerError::loop_body_contains_async("function call", input.span()));
2163 }
2164
2165 if slf.scope_state.already_contains_an_async_block {
2166 slf.emit_err(TypeCheckerError::loop_body_contains_async("block expression", input.span()));
2167 }
2168
2169 slf.scope_state.has_return = prior_has_return;
2170 slf.scope_state.has_called_finalize = prior_has_finalize;
2171 });
2172 }
2173
2174 fn visit_return(&mut self, input: &ReturnStatement) {
2175 if self.async_block_id.is_some() {
2176 return self.emit_err(TypeCheckerError::async_block_cannot_return(input.span()));
2177 }
2178
2179 if self.scope_state.is_constructor {
2180 if !matches!(input.expression, Expression::Unit(..)) {
2182 self.emit_err(TypeCheckerError::constructor_can_only_return_unit(&input.expression, input.span));
2183 }
2184 return;
2185 }
2186
2187 let caller_name = self.scope_state.function.expect("`self.function` is set every time a function is visited.");
2188 let caller_path =
2189 self.scope_state.module_name.iter().cloned().chain(std::iter::once(caller_name)).collect::<Vec<Symbol>>();
2190
2191 let func_symbol = self
2192 .state
2193 .symbol_table
2194 .lookup_function(&Location::new(self.scope_state.program_name.unwrap(), caller_path.clone()))
2195 .expect("The symbol table creator should already have visited all functions.");
2196
2197 let mut return_type = func_symbol.function.output_type.clone();
2198
2199 if self.scope_state.variant == Some(Variant::AsyncTransition) && self.scope_state.has_called_finalize {
2200 let inferred_future_type = Future(FutureType::new(
2201 if let Some(finalizer) = &func_symbol.finalizer { finalizer.inferred_inputs.clone() } else { vec![] },
2202 Some(Location::new(self.scope_state.program_name.unwrap(), caller_path)),
2203 true,
2204 ));
2205
2206 let inferred = match return_type.clone() {
2209 Future(_) => inferred_future_type,
2210 Tuple(tuple) => Tuple(TupleType::new(
2211 tuple
2212 .elements()
2213 .iter()
2214 .map(|t| if matches!(t, Future(_)) { inferred_future_type.clone() } else { t.clone() })
2215 .collect::<Vec<Type>>(),
2216 )),
2217 _ => {
2218 return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
2219 }
2220 };
2221
2222 return_type = self.assert_and_return_type(inferred, &Some(return_type), input.span());
2224 }
2225
2226 if matches!(input.expression, Expression::Unit(..)) {
2227 if return_type != Type::Unit {
2229 return self.emit_err(TypeCheckerError::missing_return(input.span()));
2233 }
2234 }
2235
2236 self.visit_expression(&input.expression, &Some(return_type));
2237
2238 self.scope_state.has_return = true;
2241 }
2242}