Refactor type checking for functions and operators
This commit refactors the type checking logic for functions and operators to improve type safety and expressiveness. Key changes include: - Introduced `StaticType::FunctionOverloads` to represent functions with multiple possible signatures, enabling better handling of operator overloading. - Updated the `TypeChecker` to correctly infer function types and resolve calls with overloaded functions. - Modified the `Environment` to register standard library functions with specific `FunctionOverloads` signatures, replacing the previous `StaticType::Any` approach. - Enhanced the `StaticType::resolve_call` method to intelligently match argument types against expected parameters, including handling of overloaded functions. - Added new tests to verify the correctness of type inference for lambda returns and operator overloading.
This commit is contained in:
@@ -155,10 +155,10 @@ impl TypeChecker {
|
||||
let ret_ty = body_typed.ty.clone();
|
||||
|
||||
// 4. Construct function type: fn(any ... any) -> Ret
|
||||
let fn_ty = StaticType::Function {
|
||||
let fn_ty = StaticType::Function(Box::new(crate::ast::types::Signature {
|
||||
params: vec![StaticType::Any; param_count as usize],
|
||||
ret: Box::new(ret_ty),
|
||||
};
|
||||
ret: ret_ty,
|
||||
}));
|
||||
|
||||
(BoundKind::Lambda {
|
||||
param_count,
|
||||
@@ -174,10 +174,8 @@ impl TypeChecker {
|
||||
typed_args.push(self.check_node(arg, ctx)?);
|
||||
}
|
||||
|
||||
let ret_ty = match &callee_typed.ty {
|
||||
StaticType::Function { ret, .. } => *ret.clone(),
|
||||
_ => StaticType::Any,
|
||||
};
|
||||
let arg_types: Vec<_> = typed_args.iter().map(|a| a.ty.clone()).collect();
|
||||
let ret_ty = callee_typed.ty.resolve_call(&arg_types).unwrap_or(StaticType::Any);
|
||||
|
||||
(BoundKind::Call {
|
||||
callee: Box::new(callee_typed),
|
||||
@@ -229,19 +227,11 @@ impl TypeChecker {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::parser::Parser;
|
||||
use crate::ast::compiler::binder::Binder;
|
||||
use crate::ast::types::StaticType;
|
||||
use std::cell::RefCell;
|
||||
|
||||
fn check_source(source: &str) -> TypedNode {
|
||||
let mut parser = Parser::new(source).unwrap();
|
||||
let untyped = parser.parse_expression().unwrap();
|
||||
let globals = Rc::new(RefCell::new(HashMap::new()));
|
||||
let bound = Binder::bind_root(globals, &untyped).unwrap();
|
||||
let global_types = Rc::new(RefCell::new(HashMap::new()));
|
||||
let checker = TypeChecker::new(global_types);
|
||||
checker.check(bound).unwrap()
|
||||
let env = crate::ast::environment::Environment::new();
|
||||
env.compile(source).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -273,14 +263,14 @@ mod tests {
|
||||
fn test_inference_lambda_return() {
|
||||
// (fn [a] 10) -> fn(any) -> Int
|
||||
let typed = check_source("(fn [a] 10)");
|
||||
if let StaticType::Function { ret, .. } = typed.ty {
|
||||
assert_eq!(*ret, StaticType::Int);
|
||||
if let StaticType::Function(sig) = typed.ty {
|
||||
assert_eq!(sig.ret, StaticType::Int);
|
||||
} else { panic!("Expected function type, got {:?}", typed.ty); }
|
||||
|
||||
// Nested: (fn [] (do 1 2.5)) -> fn() -> Float
|
||||
let typed_nested = check_source("(fn [] (do 1 2.5))");
|
||||
if let StaticType::Function { ret, .. } = typed_nested.ty {
|
||||
assert_eq!(*ret, StaticType::Float);
|
||||
if let StaticType::Function(sig) = typed_nested.ty {
|
||||
assert_eq!(sig.ret, StaticType::Float);
|
||||
} else { panic!("Expected function type"); }
|
||||
}
|
||||
|
||||
@@ -293,4 +283,12 @@ mod tests {
|
||||
assert_eq!(last_expr.ty, StaticType::Float, "Variable 'x' should be specialized to Float after assignment");
|
||||
} else { panic!("Expected block"); }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_operator_overloading_inference() {
|
||||
assert_eq!(check_source("(+ 1 2)").ty, StaticType::Int);
|
||||
assert_eq!(check_source("(+ 1.0 2.0)").ty, StaticType::Float);
|
||||
assert_eq!(check_source("(+ \"a\" \"b\")").ty, StaticType::Text);
|
||||
assert_eq!(check_source("(/ 1 2)").ty, StaticType::Float);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user