diff options
Diffstat (limited to 'src/type')
-rw-r--r-- | src/type/check.rs | 67 | ||||
-rw-r--r-- | src/type/conversion.rs | 54 |
2 files changed, 80 insertions, 41 deletions
diff --git a/src/type/check.rs b/src/type/check.rs index 77420e3..874db58 100644 --- a/src/type/check.rs +++ b/src/type/check.rs @@ -31,7 +31,9 @@ impl SExp { /// Ok(List(vec![QuoteTy, List(vec![Integer, Boolean])])) /// ); /// ``` - /// Though so is Nil given too: + /// + /// Even though Nil is formatted as an empty list, + /// it has its own type. /// ```rust /// use myslip::{ /// r#type::{*, Type::*, TypeError::*, util::*}, @@ -40,7 +42,7 @@ impl SExp { /// /// assert_eq!( /// Atom(Nil).type_check(), - /// Ok(List(vec![])) + /// Ok(NilType) /// ); /// ``` /// @@ -184,7 +186,7 @@ impl SExp { Ok(arr(List(vec![Integer, Integer]), Boolean)), Atom(Or | And | Xor) => Ok(arr(List(vec![Boolean, Boolean]), Boolean)), Atom(Not) => Ok(arr(List(vec!(Boolean)), Boolean)), - Atom(Nil) => Ok(List(vec![])), + Atom(Nil) => Ok(NilType), Atom(Quote) => Ok(arr( vt("T"), List(vec![QuoteTy, vt("T")]) @@ -216,38 +218,40 @@ impl SExp { let opertype = (*op).infer_type(ctx.clone())?; let argstype = (*l).infer_list_type(ctx)?; - - let argstype = if opertype == arr( - vecof(vt("T")), - List(vec![VecType, vecof(vt("T"))]) - ) { // hacky... - argstype.list_to_vec().ok_or( - InvalidArgList { - arglist: (**l).clone(), - expected: vecof(vt("?")), - found: argstype - } - )? - } else { - argstype - }; + let conv_args = match (opertype.clone(), argstype.clone()) { + (Arrow(from, _), a) => match a.clone().into_type(&*from) { + Ok(s) => Ok(s), + Err(()) => Err(InvalidArgList { + arglist: (**l).clone(), + expected: *from, + found: a, + }) + }, + (a, _) => { + Err(InvalidOperator { + operator: *op.clone(), + expected: arr(vt("_"), vt("_")), + found: a, + }) + } + }?; let opertype = if opertype.is_concrete().is_ok() { opertype } else { - opertype.infer_generics(&argstype)? + opertype.infer_generics(&conv_args)? }; match (opertype, argstype) { (Arrow(a, b), c) => { - if *a != c { + if c.aka(&*a) { + Ok(*b) + } else { Err(InvalidArgList { arglist: (**l).clone(), expected: *a, found: c, }) - } else { - Ok(*b) } }, (t, _) => Err(InvalidOperator { @@ -353,25 +357,6 @@ impl Type { } } - fn list_to_vec(&self) -> Option<Type> { - println!("list to vec:"); - match self { - List(tv) => match tv.get(0) { - Some(t1) => if tv.into_iter().all(|t| t == t1) { - Some(vecof(t1.clone())) - } else { - println!("all elements not of same type"); - None - }, - None => Some(vecof(vt("T"))), - }, - _ => { - println!("not a list"); - None - } - } - } - } diff --git a/src/type/conversion.rs b/src/type/conversion.rs index a819409..3be2874 100644 --- a/src/type/conversion.rs +++ b/src/type/conversion.rs @@ -71,6 +71,60 @@ impl Type { } + /// Tries to convert this type into a subtype of the other. + /// + /// ```rust + /// use myslip::r#type::{Type::*, util::*}; + /// + /// assert_eq!(Integer.into_type(&Boolean), Err(())); + /// assert_eq!(Integer.into_type(&Integer), Ok(Integer)); + /// assert_eq!(Integer.into_type(&vt("T")), Ok(Integer)); + /// assert_eq!( + /// List(vec![Integer, Integer]).into_type(&vecof(Integer)), + /// Ok(vecof(Integer)) + /// ); + /// assert_eq!( + /// List(vec![Integer, Integer]).into_type(&vecof(vt("T"))), + /// Ok(vecof(Integer)) + /// ); + /// assert_eq!( + /// List(vec![Integer, Boolean]).into_type(&vecof(vt("T"))), + /// Ok(vecof(vt("T"))) + /// ); + /// ``` + pub fn into_type(self, other: &Type) -> Result<Type, ()> { + if !self.aka(other) { + return Err(()); + } + + match (&self, other) { + + (a, b) if a == b => Ok(self), + + (_, VarType(_)) => Ok(self), + + (List(v), VecOf(b)) => match v.get(0) { + Some(first) => { + let cand = v.into_iter() + .fold(first.clone(), |a, b| a.least_general_supertype(b)); + if cand.aka(b) { + Ok(vecof(cand)) + } else { + Err(()) + } + }, + None => if NilType.aka(b) { + Ok(vecof(NilType)) + } else { + Err(()) + }, + }, + + _ => Err(()) + + } + } + } #[cfg(test)] |