From ac9ecc754e12487eb20a615ca3cf05cb163ea75a Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sun, 3 Aug 2025 16:06:43 +0300 Subject: Changed UndefinedType to VarType(String) for generics and added tests for inferring them. Inferring is done by method Type::infer_generics. Whether it is executed is controlled by method Type::is_concrete. Also had to change the Display for Type and its tests, as the enum variants changed. --- src/type/check.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 3 deletions(-) (limited to 'src/type/check.rs') diff --git a/src/type/check.rs b/src/type/check.rs index 8d2a35d..6e7e557 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -131,11 +131,16 @@ impl SExp { Atom(Nil) => Ok(List(vec![])), Atom(Quote) => Ok(List(vec![])), // TODO make it all identity functions - SCons(op, l) if **op == Atom(Quote) => (*l).infer_list_type(ctx), - SCons(op, l) => { let opertype = (*op).infer_type(ctx.clone())?; let argstype = (*l).infer_list_type(ctx)?; + + let opertype = if opertype.is_concrete() { + opertype + } else { + opertype.infer_generics(&argstype)? + }; + match (opertype, argstype) { (Arrow(a, b), c) => { if *a != c { @@ -150,7 +155,10 @@ impl SExp { }, (t, _) => Err(InvalidOperator { operator: *op.clone(), - expected: arr(UndefinedType, UndefinedType), + expected: arr( + VarType(String::from("_")), + VarType(String::from("_")) + ), found: t, }), } @@ -169,3 +177,86 @@ impl SExp { } } + + +impl Type { + + /// Infers the type of generic 'VarType's using type of arguments. + /// + /// In case there generic variables that can't be inferred, + /// returns an TypeError::UnboundVariable. + fn infer_generics(self, argtype: &Type) -> Result { + todo!() + } + +} + + +#[cfg(test)] +mod tests { + use super::{*, Type::*, TypeError}; + use crate::r#type::util::*; + + #[test] + fn test_failing_infer_generics() { + assert_eq!( + arr(Integer, VarType("X".to_string())).infer_generics(&Integer), + Err(TypeError::UnboundGeneric(String::from("X"))) + ); + } + + #[test] + fn test_infer_generics() { + + // Simple identity function, really all we + // care about (this language doesn't attempt + // to have useful generic programming capabilities, + // but some simple features are required for typing + // quotes)... + assert_eq!( + arr(VarType("T".to_string()), VarType("T".to_string())).infer_generics(&Integer), + Ok(arr(Integer, Integer)) + ); + + // ...but let's make it work for other simple cases too, + // maybe someone finds use for these. + assert_eq!( + arr( + List(vec![Integer, VarType("T".to_string())]), + List(vec![VarType("T".to_string()), Integer]) + ).infer_generics( + &List(vec![Integer, arr(Integer, Integer)]) + ), + Ok(arr( + List(vec![Integer, arr(Integer, Integer)]), + List(vec![arr(Integer, Integer), Integer]) + )) + ); + + assert_eq!( + arr(VarType("T".to_string()), Integer).infer_generics(&List(vec![Integer])), + Ok(arr(List(vec![Integer]), Integer)) + ); + + assert_eq!( + arr(List(vec![VarType("A".to_string()), VarType("B".to_string())]), VarType("B".to_string())) + .infer_generics(&List(vec![Integer, arr(Integer, Integer)])), + Ok(arr( + List(vec![List(vec![Integer, arr(Integer, Integer)])]), + arr(Integer, Integer) + )) + ); + + assert_eq!( + arr( + arr(VarType("A".to_string()), VarType("B".to_string())), + arr(VarType("B".to_string()), VarType("A".to_string())) + ).infer_generics(&arr(Integer, arr(Integer, Integer))), + Ok(arr( + arr(Integer, arr(Integer, Integer)), + arr(arr(Integer, Integer), Integer) + )) + ); + + } +} -- cgit v1.2.3