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:
+88
-26
@@ -88,50 +88,112 @@ impl Environment {
|
||||
}
|
||||
|
||||
fn register_stdlib(&self) {
|
||||
self.register_native("+", StaticType::Any, |args| {
|
||||
let mut acc = 0.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc += i as f64; }
|
||||
else if let Value::Float(f) = arg { acc += f; }
|
||||
use crate::ast::types::Signature;
|
||||
|
||||
let plus_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::Text, StaticType::Text], ret: StaticType::Text },
|
||||
]);
|
||||
self.register_native("+", plus_ty, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a + b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a + b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 + b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a + *b as f64),
|
||||
(Value::Text(a), Value::Text(b)) => {
|
||||
let mut res = a.to_string();
|
||||
res.push_str(b);
|
||||
Value::Text(Rc::from(res))
|
||||
}
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
let mut acc = 0.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc += i as f64; }
|
||||
else if let Value::Float(f) = arg { acc += f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
});
|
||||
|
||||
self.register_native("-", StaticType::Any, |args| {
|
||||
let minus_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float], ret: StaticType::Float },
|
||||
]);
|
||||
self.register_native("-", minus_ty, |args| {
|
||||
if args.is_empty() { return Value::Void; }
|
||||
if args.len() == 1 {
|
||||
return match args[0] {
|
||||
Value::Int(i) => Value::Int(-i),
|
||||
Value::Float(f) => Value::Float(-f),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
if args.len() == 2 {
|
||||
return match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a - b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a - b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 - b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a - *b as f64),
|
||||
_ => Value::Void,
|
||||
};
|
||||
}
|
||||
let mut acc = match args[0] {
|
||||
Value::Int(i) => i as f64,
|
||||
Value::Float(f) => f,
|
||||
_ => return Value::Void,
|
||||
};
|
||||
if args.len() == 1 {
|
||||
acc = -acc;
|
||||
} else {
|
||||
for arg in &args[1..] {
|
||||
if let Value::Int(i) = arg { acc -= *i as f64; }
|
||||
else if let Value::Float(f) = arg { acc -= f; }
|
||||
for arg in &args[1..] {
|
||||
if let Value::Int(i) = arg { acc -= *i as f64; }
|
||||
else if let Value::Float(f) = arg { acc -= f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
});
|
||||
|
||||
let mult_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Int },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
]);
|
||||
self.register_native("*", mult_ty, |args| {
|
||||
if args.len() == 2 {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Int(a * b),
|
||||
(Value::Float(a), Value::Float(b)) => Value::Float(a * b),
|
||||
(Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 * b),
|
||||
(Value::Float(a), Value::Int(b)) => Value::Float(a * *b as f64),
|
||||
_ => Value::Void,
|
||||
}
|
||||
} else {
|
||||
let mut acc = 1.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc *= i as f64; }
|
||||
else if let Value::Float(f) = arg { acc *= f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
});
|
||||
|
||||
self.register_native("*", StaticType::Any, |args| {
|
||||
let mut acc = 1.0;
|
||||
for arg in args {
|
||||
if let Value::Int(i) = arg { acc *= i as f64; }
|
||||
else if let Value::Float(f) = arg { acc *= f; }
|
||||
}
|
||||
if acc.fract() == 0.0 { Value::Int(acc as i64) } else { Value::Float(acc) }
|
||||
});
|
||||
|
||||
self.register_native("/", StaticType::Any, |args| {
|
||||
let div_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Float },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Float },
|
||||
]);
|
||||
self.register_native("/", div_ty, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
let a = match args[0] { Value::Int(i) => i as f64, Value::Float(f) => f, _ => return Value::Void };
|
||||
let b = match args[1] { Value::Int(i) => i as f64, Value::Float(f) => f, _ => return Value::Void };
|
||||
Value::Float(a / b)
|
||||
});
|
||||
|
||||
self.register_native(">", StaticType::Any, |args| {
|
||||
let cmp_ty = StaticType::FunctionOverloads(vec![
|
||||
Signature { params: vec![StaticType::Int, StaticType::Int], ret: StaticType::Bool },
|
||||
Signature { params: vec![StaticType::Float, StaticType::Float], ret: StaticType::Bool },
|
||||
]);
|
||||
self.register_native(">", cmp_ty.clone(), |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a > b),
|
||||
@@ -142,7 +204,7 @@ impl Environment {
|
||||
}
|
||||
});
|
||||
|
||||
self.register_native("<", StaticType::Any, |args| {
|
||||
self.register_native("<", cmp_ty, |args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => Value::Bool(a < b),
|
||||
|
||||
Reference in New Issue
Block a user