Various cleanup of comments, stringifying types
This commit is contained in:
parent
5bac01cf20
commit
e501f4bd10
@ -1,8 +1,5 @@
|
||||
use std::rc::Rc;
|
||||
//THINGS TODO
|
||||
// look at the haskell compiler, see where in its flow the typechecking happens
|
||||
// -nope, ghc deliberately does typechecking before desugaring to core
|
||||
// cf. a history of haskell, peyton-jones
|
||||
use std::fmt::Write;
|
||||
|
||||
use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable, EqUnifyValue};
|
||||
|
||||
@ -10,9 +7,6 @@ use crate::ast::*;
|
||||
use crate::util::ScopeStack;
|
||||
use crate::builtin::{PrefixOp, BinOp};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TypeData {
|
||||
@ -40,7 +34,7 @@ type InferResult<T> = Result<T, TypeError>;
|
||||
pub struct TypeError { pub msg: String }
|
||||
|
||||
impl TypeError {
|
||||
fn new<A, T>(msg: T) -> InferResult<A> where T: Into<String> { //TODO make these kinds of error-producing functions CoW-ready
|
||||
fn new<A, T>(msg: T) -> InferResult<A> where T: Into<String> {
|
||||
Err(TypeError { msg: msg.into() })
|
||||
}
|
||||
}
|
||||
@ -81,28 +75,56 @@ pub enum TypeConst {
|
||||
UserDefined
|
||||
}
|
||||
|
||||
impl TypeConst {
|
||||
pub fn to_string(&self) -> String {
|
||||
use self::TypeConst::*;
|
||||
match self {
|
||||
Unit => format!("()"),
|
||||
Nat => format!("Nat"),
|
||||
Int => format!("Int"),
|
||||
Float => format!("Float"),
|
||||
StringT => format!("String"),
|
||||
Bool => format!("Bool"),
|
||||
Ordering => format!("Ordering"),
|
||||
_ => format!("UNKNOWN TYPE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EqUnifyValue for TypeConst { }
|
||||
|
||||
macro_rules! ty {
|
||||
($type_name:ident) => { Type::Const(TypeConst::$type_name) };
|
||||
($t1:ident -> $t2:ident) => { Type::Arrow { params: vec![ty!($t1)], ret: box ty!($t2) } };
|
||||
($t1:ident -> $t2:ident -> $t3:ident) => { Type::Arrow { params: vec![ty!($t1), ty!($t2)], ret: box ty!($t3) } };
|
||||
($type_list:ident, $ret_type:ident) => {
|
||||
Type::Arrow {
|
||||
params: $type_list,
|
||||
ret: box $ret_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO find a better way to capture the to/from string logic
|
||||
impl Type {
|
||||
pub fn to_string(&self) -> String {
|
||||
use self::Type::*;
|
||||
use self::TypeConst::*;
|
||||
match self {
|
||||
Const(Unit) => format!("()"),
|
||||
Const(Nat) => format!("Nat"),
|
||||
Const(Int) => format!("Int"),
|
||||
Const(Float) => format!("Float"),
|
||||
Const(StringT) => format!("String"),
|
||||
Const(Bool) => format!("Bool"),
|
||||
Const(Ordering) => format!("Ordering"),
|
||||
_ => format!("UNKNOWN TYPE"),
|
||||
Const(c) => c.to_string(),
|
||||
Var(v) => format!("t_{}", v.0),
|
||||
Arrow { params, box ref ret } => {
|
||||
if params.len() == 0 {
|
||||
format!("-> {}", ret.to_string())
|
||||
} else {
|
||||
let mut buf = String::new();
|
||||
for p in params.iter() {
|
||||
write!(buf, "{} -> ", p.to_string());
|
||||
}
|
||||
write!(buf, "{}", ret.to_string());
|
||||
buf
|
||||
}
|
||||
},
|
||||
Compound { .. } => format!("<some compound type>")
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,6 +250,9 @@ impl<'a> TypeContext<'a> {
|
||||
|
||||
}
|
||||
|
||||
/// `typecheck` is the entry into the type-inference system, accepting an AST as an argument
|
||||
/// Following the example of GHC, the compiler deliberately does typechecking before de-sugaring
|
||||
/// the AST to ReducedAST
|
||||
pub fn typecheck(&mut self, ast: &AST) -> Result<Type, TypeError> {
|
||||
let mut returned_type = Type::Const(TypeConst::Unit);
|
||||
for statement in ast.0.iter() {
|
||||
@ -334,11 +359,12 @@ impl<'a> TypeContext<'a> {
|
||||
}
|
||||
}).collect();
|
||||
let argument_types = argument_types?;
|
||||
let ret_type = match type_anno.as_ref() {
|
||||
Some(anno) => self.get_type_from_name(anno)?,
|
||||
None => Type::Var(self.fresh_type_variable())
|
||||
};
|
||||
|
||||
println!("ARGUMENT TYPES: {:?}", argument_types);
|
||||
|
||||
//TODO finish this
|
||||
Ok(ty!(UserDefined))
|
||||
Ok(ty!(argument_types, ret_type))
|
||||
}
|
||||
|
||||
fn call(&mut self, f: &Expression, args: &Vec<Meta<Expression>>) -> InferResult<Type> {
|
||||
@ -379,7 +405,6 @@ impl<'a> TypeContext<'a> {
|
||||
|
||||
fn unify(&mut self, t1: Type, t2: Type) -> InferResult<Type> {
|
||||
use self::Type::*;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
match (t1, t2) {
|
||||
(Const(ref c1), Const(ref c2)) if c1 == c2 => Ok(Const(c1.clone())), //choice of c1 is arbitrary I *think*
|
||||
|
Loading…
Reference in New Issue
Block a user