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