From ccb4c0f38faa62651f6d41245de675269a33d280 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Fri, 23 Jun 2023 10:10:10 -0400 Subject: [PATCH] Implement type checking for cast expressions --- .../passes/src/type_checking/check_expressions.rs | 14 ++++++++++++++ compiler/passes/src/type_checking/checker.rs | 14 ++++++++++++++ .../src/errors/type_checker/type_checker_error.rs | 7 +++++++ 3 files changed, 35 insertions(+) diff --git a/compiler/passes/src/type_checking/check_expressions.rs b/compiler/passes/src/type_checking/check_expressions.rs index 11185306e3..0205ccdd52 100644 --- a/compiler/passes/src/type_checking/check_expressions.rs +++ b/compiler/passes/src/type_checking/check_expressions.rs @@ -512,6 +512,20 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> { } } + fn visit_cast(&mut self, input: &'a CastExpression, expected: &Self::AdditionalInput) -> Self::Output { + // Check that the target type of the cast expression is a primitive type. + if !Self::is_primitive_type(&input.type_) { + self.emit_err(TypeCheckerError::cast_must_be_to_primitive(input.span())); + } + // Check that the expression being casted matches the target type. + let target_type = input.type_.clone(); + let expression_type = self.visit_expression(&input.expression, &None); + self.assert_type(&expression_type, &target_type, input.expression.span()); + + // Check that the expected type matches the target type. + Some(self.assert_and_return_type(target_type, expected, input.span())) + } + fn visit_struct_init(&mut self, input: &'a StructExpression, additional: &Self::AdditionalInput) -> Self::Output { let struct_ = self.symbol_table.borrow().lookup_struct(input.name.name).cloned(); if let Some(struct_) = struct_ { diff --git a/compiler/passes/src/type_checking/checker.rs b/compiler/passes/src/type_checking/checker.rs index 4d20f2902a..dc9628a8ae 100644 --- a/compiler/passes/src/type_checking/checker.rs +++ b/compiler/passes/src/type_checking/checker.rs @@ -163,6 +163,20 @@ impl<'a> TypeChecker<'a> { } } + /// Returns whether the given type is a primitive type. + pub(crate) fn is_primitive_type(type_: &Type) -> bool { + match type_ { + Type::Address + | Type::Boolean + | Type::Field + | Type::Group + | Type::Integer(_) + | Type::Scalar + | Type::String => true, + Type::Identifier(_) | Type::Mapping(_) | Type::Tuple(_) | Type::Unit | Type::Err => false, + } + } + /// Use this method when you know the actual type. /// Emits an error to the handler if the `actual` type is not equal to the `expected` type. pub(crate) fn assert_and_return_type(&self, actual: Type, expected: &Option, span: Span) -> Type { diff --git a/errors/src/errors/type_checker/type_checker_error.rs b/errors/src/errors/type_checker/type_checker_error.rs index 3675e23582..ffb97f3689 100644 --- a/errors/src/errors/type_checker/type_checker_error.rs +++ b/errors/src/errors/type_checker/type_checker_error.rs @@ -635,4 +635,11 @@ create_messages!( msg: format!("`{operation}` is not a valid operand in a finalize context."), help: None, } + + @formatted + cast_must_be_to_primitive { + args: (), + msg: format!("A cast must be to a primitive type."), + help: None, + } );