aboutsummaryrefslogtreecommitdiff
path: root/src/type/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/type/check.rs')
-rw-r--r--src/type/check.rs97
1 files changed, 94 insertions, 3 deletions
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<Type, TypeError> {
+ 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)
+ ))
+ );
+
+ }
+}