Add type inference tests
Adds a suite of tests to verify type inference for constants, variable propagation, block expressions, lambda return types, and assignment updates.
This commit is contained in:
@@ -225,3 +225,72 @@ 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()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inference_constants() {
|
||||
assert_eq!(check_source("10").ty, StaticType::Int);
|
||||
assert_eq!(check_source("10.5").ty, StaticType::Float);
|
||||
assert_eq!(check_source("true").ty, StaticType::Bool);
|
||||
assert_eq!(check_source("\"hello\"").ty, StaticType::Text);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inference_variable_propagation() {
|
||||
// (do (def x 10) x) -> The last 'x' must be Int
|
||||
let typed = check_source("(do (def x 10) x)");
|
||||
if let BoundKind::Block { exprs } = typed.kind {
|
||||
let last_expr = exprs.last().unwrap();
|
||||
assert_eq!(last_expr.ty, StaticType::Int, "Variable 'x' should be inferred as Int");
|
||||
} else { panic!("Expected block"); }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inference_block_type() {
|
||||
// Block type = last expression type
|
||||
assert_eq!(check_source("(do 1 2.5)").ty, StaticType::Float);
|
||||
assert_eq!(check_source("(do 1.5 \"test\")").ty, StaticType::Text);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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);
|
||||
} 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);
|
||||
} else { panic!("Expected function type"); }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inference_assignment_updates_type() {
|
||||
// (do (def x 10) (assign x 20.5) x) -> x becomes Float after assignment
|
||||
let typed = check_source("(do (def x 10) (assign x 20.5) x)");
|
||||
if let BoundKind::Block { exprs } = typed.kind {
|
||||
let last_expr = exprs.last().unwrap();
|
||||
assert_eq!(last_expr.ty, StaticType::Float, "Variable 'x' should be specialized to Float after assignment");
|
||||
} else { panic!("Expected block"); }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user