2018-02-21 02:31:28 -08:00
|
|
|
use std::rc::Rc;
|
2019-02-10 12:21:12 -08:00
|
|
|
//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
|
2018-02-21 02:31:28 -08:00
|
|
|
|
2019-02-23 00:59:58 -08:00
|
|
|
use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable, EqUnifyValue};
|
2019-02-23 00:34:44 -08:00
|
|
|
|
2019-01-07 13:00:37 -08:00
|
|
|
use crate::ast::*;
|
|
|
|
use crate::util::ScopeStack;
|
2019-02-20 01:33:45 -08:00
|
|
|
use crate::builtin::{PrefixOp, BinOp};
|
2018-11-06 13:44:52 -08:00
|
|
|
|
2019-02-23 00:34:44 -08:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::hash::Hash;
|
|
|
|
|
|
|
|
|
2019-02-21 01:46:27 -08:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub struct TypeData {
|
|
|
|
ty: Option<Type>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeData {
|
|
|
|
pub fn new() -> TypeData {
|
|
|
|
TypeData { ty: None }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-27 02:44:06 -07:00
|
|
|
pub type TypeName = Rc<String>;
|
2018-11-06 13:44:52 -08:00
|
|
|
|
2018-11-08 20:30:17 -08:00
|
|
|
pub struct TypeContext<'a> {
|
2019-02-15 21:11:50 -08:00
|
|
|
variable_map: ScopeStack<'a, Rc<String>, Type>,
|
2019-02-23 00:34:44 -08:00
|
|
|
unification_table: InPlaceUnificationTable<TypeVar>,
|
2019-02-10 05:33:55 -08:00
|
|
|
//evar_count: u32
|
2018-11-06 13:44:52 -08:00
|
|
|
}
|
|
|
|
|
2018-11-11 18:04:44 -08:00
|
|
|
/// `InferResult` is the monad in which type inference takes place.
|
2018-11-07 17:01:07 -08:00
|
|
|
type InferResult<T> = Result<T, TypeError>;
|
2018-11-06 16:47:34 -08:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2019-02-20 01:33:45 -08:00
|
|
|
pub struct TypeError { pub msg: String }
|
2018-11-08 02:26:02 -08:00
|
|
|
|
|
|
|
impl TypeError {
|
2019-02-20 02:05:24 -08:00
|
|
|
fn new<A, T>(msg: T) -> InferResult<A> where T: Into<String> { //TODO make these kinds of error-producing functions CoW-ready
|
|
|
|
Err(TypeError { msg: msg.into() })
|
2018-11-08 02:26:02 -08:00
|
|
|
}
|
|
|
|
}
|
2018-11-06 16:47:34 -08:00
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
2019-02-10 04:30:37 -08:00
|
|
|
pub enum Type {
|
|
|
|
Const(TypeConst),
|
2019-02-21 01:17:34 -08:00
|
|
|
Var(TypeVar),
|
2019-02-17 04:30:49 -08:00
|
|
|
Arrow(Box<Type>, Box<Type>),
|
|
|
|
Compound {
|
2019-02-21 01:17:34 -08:00
|
|
|
ty_name: String,
|
2019-02-17 04:30:49 -08:00
|
|
|
args:Vec<Type>
|
|
|
|
}
|
2019-02-10 04:30:37 -08:00
|
|
|
}
|
|
|
|
|
2019-02-23 00:34:44 -08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct TypeVar(usize);
|
|
|
|
|
|
|
|
impl UnifyKey for TypeVar {
|
2019-02-23 00:59:58 -08:00
|
|
|
type Value = Option<TypeConst>;
|
2019-02-23 00:34:44 -08:00
|
|
|
fn index(&self) -> u32 { self.0 as u32 }
|
|
|
|
fn from_index(u: u32) -> TypeVar { TypeVar(u as usize) }
|
|
|
|
fn tag() -> &'static str { "TypeVar" }
|
|
|
|
}
|
2019-02-21 01:17:34 -08:00
|
|
|
|
2019-02-23 00:59:58 -08:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2019-02-10 04:30:37 -08:00
|
|
|
pub enum TypeConst {
|
|
|
|
Unit,
|
|
|
|
Nat,
|
|
|
|
Int,
|
|
|
|
Float,
|
|
|
|
StringT,
|
|
|
|
Bool,
|
2019-02-10 07:06:30 -08:00
|
|
|
Ordering,
|
2019-02-10 04:30:37 -08:00
|
|
|
UserDefined
|
|
|
|
}
|
|
|
|
|
2019-02-23 00:59:58 -08:00
|
|
|
impl EqUnifyValue for TypeConst { }
|
|
|
|
|
2019-02-17 04:25:38 -08:00
|
|
|
macro_rules! ty {
|
|
|
|
($type_name:ident) => { Type::Const(TypeConst::$type_name) };
|
|
|
|
($t1:ident -> $t2:ident) => { Type::Arrow(Box::new(ty!($t1)), Box::new(ty!($t2))) };
|
|
|
|
($t1:ident -> $t2:ident -> $t3:ident) => { Type::Arrow(Box::new(ty!($t1)), Box::new(ty!($t2 -> $t3))) };
|
|
|
|
}
|
|
|
|
|
2019-02-10 07:05:01 -08:00
|
|
|
//TODO find a better way to capture the to/from string logic
|
2019-02-10 04:30:37 -08:00
|
|
|
impl Type {
|
2019-02-20 01:33:45 -08:00
|
|
|
pub fn to_string(&self) -> String {
|
2019-02-10 05:31:58 -08:00
|
|
|
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"),
|
2019-02-10 07:06:30 -08:00
|
|
|
Const(Ordering) => format!("Ordering"),
|
2019-02-10 05:31:58 -08:00
|
|
|
_ => format!("UNKNOWN TYPE"),
|
|
|
|
}
|
|
|
|
}
|
2019-02-10 07:05:01 -08:00
|
|
|
|
|
|
|
fn from_string(string: &str) -> Option<Type> {
|
|
|
|
Some(match string {
|
2019-02-17 04:25:38 -08:00
|
|
|
"()" | "Unit" => ty!(Unit),
|
|
|
|
"Nat" => ty!(Nat),
|
|
|
|
"Int" => ty!(Int),
|
|
|
|
"Float" => ty!(Float),
|
|
|
|
"String" => ty!(StringT),
|
|
|
|
"Bool" => ty!(Bool),
|
|
|
|
"Ordering" => ty!(Ordering),
|
2019-02-10 07:05:01 -08:00
|
|
|
_ => return None
|
|
|
|
})
|
|
|
|
}
|
2019-02-10 05:31:58 -08:00
|
|
|
}
|
2019-02-10 04:30:37 -08:00
|
|
|
|
2019-02-09 00:25:12 -08:00
|
|
|
/*
|
2018-11-11 18:04:44 -08:00
|
|
|
/// `Type` is parameterized by whether the type variables can be just universal, or universal or
|
|
|
|
/// existential.
|
2018-11-07 13:44:28 -08:00
|
|
|
#[derive(Debug, Clone)]
|
2018-11-09 02:50:29 -08:00
|
|
|
enum Type<A> {
|
|
|
|
Var(A),
|
2018-11-07 15:39:40 -08:00
|
|
|
Const(TConst),
|
2018-11-09 02:50:29 -08:00
|
|
|
Arrow(Box<Type<A>>, Box<Type<A>>),
|
|
|
|
}
|
|
|
|
|
2018-11-10 16:33:42 -08:00
|
|
|
#[derive(Debug, Clone)]
|
2018-11-09 02:50:29 -08:00
|
|
|
enum TVar {
|
2018-11-10 16:33:42 -08:00
|
|
|
Univ(UVar),
|
2018-11-10 14:11:29 -08:00
|
|
|
Exist(ExistentialVar)
|
2018-11-08 02:26:02 -08:00
|
|
|
}
|
|
|
|
|
2018-11-10 16:33:42 -08:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct UVar(Rc<String>);
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2018-11-09 02:50:29 -08:00
|
|
|
struct ExistentialVar(u32);
|
|
|
|
|
2018-11-10 16:33:42 -08:00
|
|
|
impl Type<UVar> {
|
|
|
|
fn to_tvar(&self) -> Type<TVar> {
|
|
|
|
match self {
|
|
|
|
Type::Var(UVar(name)) => Type::Var(TVar::Univ(UVar(name.clone()))),
|
|
|
|
Type::Const(ref c) => Type::Const(c.clone()),
|
|
|
|
Type::Arrow(a, b) => Type::Arrow(
|
|
|
|
Box::new(a.to_tvar()),
|
|
|
|
Box::new(b.to_tvar())
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Type<TVar> {
|
|
|
|
fn skolemize(&self) -> Type<UVar> {
|
|
|
|
match self {
|
|
|
|
Type::Var(TVar::Univ(uvar)) => Type::Var(uvar.clone()),
|
2018-11-13 02:39:02 -08:00
|
|
|
Type::Var(TVar::Exist(_)) => Type::Var(UVar(Rc::new(format!("sk")))),
|
2018-11-10 16:33:42 -08:00
|
|
|
Type::Const(ref c) => Type::Const(c.clone()),
|
|
|
|
Type::Arrow(a, b) => Type::Arrow(
|
|
|
|
Box::new(a.skolemize()),
|
|
|
|
Box::new(b.skolemize())
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-08 02:26:02 -08:00
|
|
|
impl TypeIdentifier {
|
2018-11-10 16:33:42 -08:00
|
|
|
fn to_monotype(&self) -> Type<UVar> {
|
2018-11-08 20:30:17 -08:00
|
|
|
match self {
|
2018-11-13 02:39:02 -08:00
|
|
|
TypeIdentifier::Tuple(_) => Type::Const(TConst::Nat),
|
2018-11-08 20:30:17 -08:00
|
|
|
TypeIdentifier::Singleton(TypeSingletonName { name, .. }) => {
|
|
|
|
match &name[..] {
|
2018-11-09 02:05:59 -08:00
|
|
|
"Nat" => Type::Const(TConst::Nat),
|
|
|
|
"Int" => Type::Const(TConst::Int),
|
|
|
|
"Float" => Type::Const(TConst::Float),
|
|
|
|
"Bool" => Type::Const(TConst::Bool),
|
|
|
|
"String" => Type::Const(TConst::StringT),
|
2018-11-13 02:39:02 -08:00
|
|
|
_ => Type::Const(TConst::Nat),
|
2018-11-08 20:30:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-08 02:26:02 -08:00
|
|
|
}
|
2018-11-07 03:39:31 -08:00
|
|
|
}
|
2018-11-06 16:47:34 -08:00
|
|
|
|
2018-11-07 15:39:40 -08:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
enum TConst {
|
|
|
|
User(Rc<String>),
|
|
|
|
Unit,
|
|
|
|
Nat,
|
2018-11-07 16:39:32 -08:00
|
|
|
Int,
|
|
|
|
Float,
|
|
|
|
StringT,
|
2018-11-08 02:12:01 -08:00
|
|
|
Bool,
|
2018-11-07 15:39:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TConst {
|
|
|
|
fn user(name: &str) -> TConst {
|
|
|
|
TConst::User(Rc::new(name.to_string()))
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 00:25:12 -08:00
|
|
|
*/
|
2018-11-07 15:39:40 -08:00
|
|
|
|
2018-11-08 20:30:17 -08:00
|
|
|
impl<'a> TypeContext<'a> {
|
|
|
|
pub fn new() -> TypeContext<'a> {
|
|
|
|
TypeContext {
|
|
|
|
variable_map: ScopeStack::new(None),
|
2019-02-23 00:34:44 -08:00
|
|
|
unification_table: UnificationTable::new(),
|
2019-02-10 05:33:55 -08:00
|
|
|
//evar_count: 0
|
2018-11-08 20:30:17 -08:00
|
|
|
}
|
2018-11-06 13:44:52 -08:00
|
|
|
}
|
|
|
|
|
2019-02-10 06:53:11 -08:00
|
|
|
fn get_type_from_name(&self, name: &TypeIdentifier) -> InferResult<Type> {
|
2019-02-10 07:05:01 -08:00
|
|
|
use self::TypeIdentifier::*;
|
|
|
|
Ok(match name {
|
|
|
|
Singleton(TypeSingletonName { name, params }) => {
|
|
|
|
match Type::from_string(&name) {
|
|
|
|
Some(ty) => ty,
|
|
|
|
None => return TypeError::new("Unknown type name")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Tuple(_) => return TypeError::new("tuples aren't ready yet"),
|
|
|
|
})
|
|
|
|
|
2019-02-10 06:53:11 -08:00
|
|
|
}
|
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
pub fn typecheck(&mut self, ast: &AST) -> Result<Type, TypeError> {
|
2019-02-10 05:15:57 -08:00
|
|
|
let mut returned_type = Type::Const(TypeConst::Unit);
|
2019-02-10 04:42:30 -08:00
|
|
|
for statement in ast.0.iter() {
|
2019-02-20 01:33:45 -08:00
|
|
|
returned_type = self.statement(statement.node())?;
|
2019-02-10 04:42:30 -08:00
|
|
|
}
|
2019-02-20 01:33:45 -08:00
|
|
|
Ok(returned_type)
|
2019-02-10 04:42:30 -08:00
|
|
|
}
|
|
|
|
|
2019-02-17 04:08:49 -08:00
|
|
|
fn statement(&mut self, statement: &Statement) -> InferResult<Type> {
|
2019-02-10 04:42:30 -08:00
|
|
|
match statement {
|
2019-02-17 04:08:49 -08:00
|
|
|
Statement::ExpressionStatement(e) => self.expr(e.node()),
|
|
|
|
Statement::Declaration(decl) => self.decl(decl),
|
2019-02-10 04:42:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 21:41:07 -08:00
|
|
|
fn decl(&mut self, decl: &Declaration) -> InferResult<Type> {
|
|
|
|
use self::Declaration::*;
|
|
|
|
match decl {
|
|
|
|
Binding { name, expr, .. } => {
|
2019-02-21 19:07:07 -08:00
|
|
|
let ty = self.expr(expr.node())?;
|
2019-02-19 21:41:07 -08:00
|
|
|
self.variable_map.insert(name.clone(), ty);
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
2019-02-17 04:25:38 -08:00
|
|
|
Ok(ty!(Unit))
|
2019-02-10 04:42:30 -08:00
|
|
|
}
|
|
|
|
|
2019-02-17 04:08:49 -08:00
|
|
|
fn expr(&mut self, expr: &Expression) -> InferResult<Type> {
|
2019-02-10 05:15:57 -08:00
|
|
|
match expr {
|
2019-02-10 06:53:11 -08:00
|
|
|
Expression(expr_type, Some(anno)) => {
|
2019-02-17 04:08:49 -08:00
|
|
|
let t1 = self.expr_type(expr_type)?;
|
2019-02-10 06:53:11 -08:00
|
|
|
let t2 = self.get_type_from_name(anno)?;
|
|
|
|
self.unify(t2, t1)
|
2019-02-10 05:15:57 -08:00
|
|
|
},
|
2019-02-17 04:08:49 -08:00
|
|
|
Expression(expr_type, None) => self.expr_type(expr_type)
|
2019-02-10 05:15:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 01:26:51 -08:00
|
|
|
fn expr_type(&mut self, expr: &ExpressionKind) -> InferResult<Type> {
|
|
|
|
use self::ExpressionKind::*;
|
2019-02-10 05:31:58 -08:00
|
|
|
Ok(match expr {
|
2019-02-17 04:25:38 -08:00
|
|
|
NatLiteral(_) => ty!(Nat),
|
|
|
|
BoolLiteral(_) => ty!(Bool),
|
|
|
|
FloatLiteral(_) => ty!(Float),
|
|
|
|
StringLiteral(_) => ty!(StringT),
|
2019-02-17 04:08:49 -08:00
|
|
|
PrefixExp(op, expr) => self.prefix(op, expr.node())?,
|
2019-02-20 01:33:45 -08:00
|
|
|
BinExp(op, lhs, rhs) => self.binexp(op, lhs.node(), rhs.node())?,
|
2019-02-17 04:08:49 -08:00
|
|
|
IfExpression { discriminator, body } => self.if_expr(discriminator, body)?,
|
2019-02-12 21:14:13 -08:00
|
|
|
Value(val) => self.handle_value(val)?,
|
2019-02-20 01:33:45 -08:00
|
|
|
Lambda { params, type_anno, body } => self.lambda(params, type_anno, body)?,
|
2019-02-17 04:25:38 -08:00
|
|
|
_ => ty!(Unit),
|
2019-02-10 05:31:58 -08:00
|
|
|
})
|
2018-11-06 13:44:52 -08:00
|
|
|
}
|
2019-02-10 06:48:25 -08:00
|
|
|
|
2019-02-17 04:08:49 -08:00
|
|
|
fn prefix(&mut self, op: &PrefixOp, expr: &Expression) -> InferResult<Type> {
|
2019-02-10 12:21:12 -08:00
|
|
|
let f = match op.get_type() {
|
|
|
|
Ok(ty) => ty,
|
2019-02-20 03:27:46 -08:00
|
|
|
Err(e) => return TypeError::new(e)
|
2019-02-10 12:21:12 -08:00
|
|
|
};
|
|
|
|
|
2019-02-17 04:08:49 -08:00
|
|
|
let x = self.expr(expr)?;
|
2019-02-10 12:21:12 -08:00
|
|
|
self.handle_apply(f, x)
|
|
|
|
}
|
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
fn binexp(&mut self, op: &BinOp, lhs: &Expression, rhs: &Expression) -> InferResult<Type> {
|
2019-02-20 03:27:46 -08:00
|
|
|
let tf = match op.get_type() {
|
|
|
|
Ok(ty) => ty,
|
|
|
|
Err(e) => return TypeError::new(e),
|
|
|
|
};
|
|
|
|
|
|
|
|
let t_lhs = self.expr(lhs)?;
|
|
|
|
let t_curried = self.handle_apply(tf, t_lhs)?;
|
|
|
|
let t_rhs = self.expr(rhs)?;
|
|
|
|
self.handle_apply(t_curried, t_rhs)
|
2019-02-10 12:21:12 -08:00
|
|
|
}
|
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
fn handle_apply(&mut self, tf: Type, tx: Type) -> InferResult<Type> {
|
|
|
|
Ok(match tf {
|
2019-02-20 03:27:46 -08:00
|
|
|
Type::Arrow(box ref t1, box ref t2) => {
|
|
|
|
let _ = self.unify(t1.clone(), tx)?;
|
|
|
|
t2.clone()
|
2019-02-20 01:33:45 -08:00
|
|
|
},
|
2019-02-20 02:05:24 -08:00
|
|
|
_ => return TypeError::new(format!("Not a function"))
|
2019-02-20 01:33:45 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-17 04:08:49 -08:00
|
|
|
fn if_expr(&mut self, discriminator: &Discriminator, body: &IfExpressionBody) -> InferResult<Type> {
|
2019-02-19 23:00:41 -08:00
|
|
|
use self::Discriminator::*; use self::IfExpressionBody::*;
|
|
|
|
match (discriminator, body) {
|
|
|
|
(Simple(expr), SimpleConditional(then_clause, else_clause)) => self.handle_simple_if(expr, then_clause, else_clause),
|
2019-02-20 02:05:24 -08:00
|
|
|
_ => TypeError::new(format!("Complex conditionals not supported"))
|
2019-02-19 23:00:41 -08:00
|
|
|
}
|
|
|
|
}
|
2019-02-10 12:21:12 -08:00
|
|
|
|
2019-02-19 23:00:41 -08:00
|
|
|
fn handle_simple_if(&mut self, expr: &Expression, then_clause: &Block, else_clause: &Option<Block>) -> InferResult<Type> {
|
|
|
|
let t1 = self.expr(expr)?;
|
|
|
|
let t2 = self.block(then_clause)?;
|
|
|
|
let t3 = match else_clause {
|
|
|
|
Some(block) => self.block(block)?,
|
|
|
|
None => ty!(Unit)
|
|
|
|
};
|
|
|
|
|
|
|
|
let _ = self.unify(ty!(Bool), t1)?;
|
|
|
|
self.unify(t2, t3)
|
|
|
|
}
|
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
fn lambda(&mut self, params: &Vec<FormalParam>, type_anno: &Option<TypeIdentifier>, body: &Block) -> InferResult<Type> {
|
2019-02-23 00:34:44 -08:00
|
|
|
|
2019-02-20 01:33:45 -08:00
|
|
|
Ok(ty!(Unit))
|
|
|
|
}
|
|
|
|
|
2019-02-19 23:00:41 -08:00
|
|
|
fn block(&mut self, block: &Block) -> InferResult<Type> {
|
|
|
|
let mut output = ty!(Unit);
|
|
|
|
for s in block.iter() {
|
|
|
|
let statement = s.node();
|
|
|
|
output = self.statement(statement)?;
|
|
|
|
}
|
|
|
|
Ok(output)
|
2019-02-10 12:21:12 -08:00
|
|
|
}
|
2019-02-10 06:48:25 -08:00
|
|
|
|
2019-02-12 21:14:13 -08:00
|
|
|
fn handle_value(&mut self, val: &Rc<String>) -> InferResult<Type> {
|
|
|
|
match self.variable_map.lookup(val) {
|
|
|
|
Some(ty) => Ok(ty.clone()),
|
2019-02-20 02:05:24 -08:00
|
|
|
None => TypeError::new(format!("Couldn't find variable: {}", val))
|
2019-02-12 21:14:13 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-10 06:53:11 -08:00
|
|
|
fn unify(&mut self, t1: Type, t2: Type) -> InferResult<Type> {
|
2019-02-21 18:39:41 -08:00
|
|
|
use self::Type::*;
|
2019-02-23 00:34:44 -08:00
|
|
|
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*
|
|
|
|
(Const(ref c1), Var(ref v2)) => {
|
2019-02-23 01:18:15 -08:00
|
|
|
self.unification_table.unify_var_value(v2.clone(), Some(c1.clone()))
|
|
|
|
.or_else(|_| TypeError::new(format!("Couldn't unify {:?} and {:?}", Const(c1.clone()), Var(*v2))))?;
|
2019-02-23 00:34:44 -08:00
|
|
|
Ok(Const(c1.clone()))
|
|
|
|
},
|
|
|
|
(a @ Var(_), b @ Const(_)) => self.unify(b, a),
|
|
|
|
(Var(v1), Var(v2)) => {
|
2019-02-23 01:20:19 -08:00
|
|
|
self.unification_table.unify_var_var(v1.clone(), v2.clone())
|
|
|
|
.or_else(|_| TypeError::new(format!("Two type variables {:?} and {:?} couldn't unify", v1, v2)))?;
|
|
|
|
Ok(Var(v1.clone())) //arbitrary decision I think
|
2019-02-23 00:34:44 -08:00
|
|
|
},
|
|
|
|
(a, b) => TypeError::new(format!("{:?} and {:?} do not unify", a, b)),
|
|
|
|
}
|
2019-02-10 06:48:25 -08:00
|
|
|
}
|
2018-11-06 13:44:52 -08:00
|
|
|
}
|
2019-02-20 01:33:45 -08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod typechecking_tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::ast::AST;
|
|
|
|
|
|
|
|
fn parse(input: &str) -> AST {
|
|
|
|
let tokens = crate::tokenizing::tokenize(input);
|
|
|
|
let mut parser = crate::parsing::Parser::new(tokens);
|
|
|
|
parser.parse().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! assert_type_in_fresh_context {
|
|
|
|
($string:expr, $type:expr) => {
|
|
|
|
let mut tc = TypeContext::new();
|
|
|
|
let ref ast = parse($string);
|
|
|
|
let ty = tc.typecheck(ast).unwrap();
|
|
|
|
assert_eq!(ty, $type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn basic_test() {
|
|
|
|
assert_type_in_fresh_context!("1", ty!(Nat));
|
|
|
|
assert_type_in_fresh_context!(r#""drugs""#, ty!(StringT));
|
|
|
|
assert_type_in_fresh_context!("true", ty!(Bool));
|
|
|
|
assert_type_in_fresh_context!("-1", ty!(Int));
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:27:46 -08:00
|
|
|
#[test]
|
|
|
|
fn operators() {
|
|
|
|
assert_type_in_fresh_context!("1 + 2", ty!(Nat));
|
|
|
|
assert_type_in_fresh_context!("-2", ty!(Int));
|
|
|
|
assert_type_in_fresh_context!("!true", ty!(Bool));
|
|
|
|
}
|
2019-02-20 01:33:45 -08:00
|
|
|
}
|