From 0df36e322790c4d1eef4bef9f99416c555c34e64 Mon Sep 17 00:00:00 2001 From: Glyphack Date: Sat, 2 Sep 2023 12:22:01 +0200 Subject: [PATCH] add callable type for functions --- typechecker/src/type_check/checker.rs | 28 ++++++++++++++++--- typechecker/src/type_check/types.rs | 6 ++-- .../testdata/inputs/type_check_call.py | 2 ++ ...hecker__build__tests__type_check_call.snap | 3 +- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/typechecker/src/type_check/checker.rs b/typechecker/src/type_check/checker.rs index da301cc6..56f3d416 100644 --- a/typechecker/src/type_check/checker.rs +++ b/typechecker/src/type_check/checker.rs @@ -7,7 +7,7 @@ use crate::{ use super::{ type_inference::{self, bin_op_result_type, type_check_bin_op}, - types::Type, + types::{CallableType, Type}, }; pub struct TypeChecker<'a> { @@ -45,11 +45,20 @@ impl<'a> TypeChecker<'a> { } } Declaration::Function(f) => { - if let Some(type_annotation) = f.function_node.returns.clone() { + let return_type = if let Some(type_annotation) = f.function_node.returns.clone() { type_inference::get_type_from_annotation(&type_annotation) } else { panic!("Infer the type based on the return statement") - } + }; + + let arguments = f.function_node.args.clone(); + let name = f.function_node.name.clone(); + + Type::Callable(Box::new(CallableType { + name, + arguments, + return_type, + })) } _ => panic!("TODO: infer type from declaration"), } @@ -85,7 +94,18 @@ impl<'a> TypeChecker<'a> { ast::Expression::Call(call) => { let func = *call.func.clone(); match func { - ast::Expression::Name(n) => self.infer_type_from_symbol_table(n.id.as_str()), + ast::Expression::Name(n) => { + let f_type = self.infer_type_from_symbol_table(n.id.as_str()); + // we know this must be a callable type otherwise raise error cannot call + match f_type { + Type::Callable(callable_type) => callable_type.return_type, + _ => { + self.errors + .push(format!("Cannot call type '{}' as a function", f_type)); + Type::Unknown + } + } + } ast::Expression::Attribute(a) => panic!("TODO: infer type from attribute"), _ => panic!("TODO: infer type from call"), } diff --git a/typechecker/src/type_check/types.rs b/typechecker/src/type_check/types.rs index 9469f8c7..0baf5caf 100644 --- a/typechecker/src/type_check/types.rs +++ b/typechecker/src/type_check/types.rs @@ -15,9 +15,9 @@ pub enum Type { #[allow(unused)] pub struct CallableType { - name: String, - arguments: ast::Arguments, - return_type: Type, + pub name: String, + pub arguments: ast::Arguments, + pub return_type: Type, } impl Display for Type { diff --git a/typechecker/testdata/inputs/type_check_call.py b/typechecker/testdata/inputs/type_check_call.py index 1a3fb27d..244c73d4 100644 --- a/typechecker/testdata/inputs/type_check_call.py +++ b/typechecker/testdata/inputs/type_check_call.py @@ -5,3 +5,5 @@ def function() -> int: b = function() + "1" c = a + 1 d = function() + 1 + +function + 1 diff --git a/typechecker/testdata/output/typechecker__build__tests__type_check_call.snap b/typechecker/testdata/output/typechecker__build__tests__type_check_call.snap index 2bf1cebf..f6432851 100644 --- a/typechecker/testdata/output/typechecker__build__tests__type_check_call.snap +++ b/typechecker/testdata/output/typechecker__build__tests__type_check_call.snap @@ -1,6 +1,7 @@ --- source: typechecker/src/build.rs -description: "def function() -> int:\n return 1\n\na = function()\nb = function() + \"1\"\nc = a + 1\nd = function() + 1\n" +description: "def function() -> int:\n return 1\n\na = function()\nb = function() + \"1\"\nc = a + 1\nd = function() + 1\n\nfunction + 1\n" expression: result --- Operator '+' not supported for types 'Int' and 'Str' +Operator '+' not supported for types 'function' and 'Int'