aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/type/check.rs67
-rw-r--r--src/type/conversion.rs54
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)]