From 9b36d699c63e482969239ed9f84779f7cd1ad2f3 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 24 Jul 2016 21:37:13 +0200 Subject: [PATCH 1/3] refactor(check): Simplify the app unification --- base/src/types.rs | 23 ++++----- check/src/kindcheck.rs | 8 +--- check/src/typecheck.rs | 15 +++--- check/src/unify_type.rs | 102 ++++++++++------------------------------ 4 files changed, 44 insertions(+), 104 deletions(-) diff --git a/base/src/types.rs b/base/src/types.rs index ff1645405a..af7502ee9e 100644 --- a/base/src/types.rs +++ b/base/src/types.rs @@ -1,4 +1,5 @@ //! Module containing types representing `gluon`'s type system +use std::borrow::ToOwned; use std::collections::HashMap; use std::fmt; use std::ops::Deref; @@ -923,20 +924,20 @@ pub fn walk_move_type(typ: T, f: &mut F) -> T /// Merges two values using `f` if either or both them is `Some(..)`. /// If both are `None`, `None` is returned. -pub fn merge(a_original: &A, - a: Option, - b_original: &B, - b: Option, - f: F) - -> Option - where A: Clone, - B: Clone, - F: FnOnce(A, B) -> R +pub fn merge(a_original: &A, + a: Option, + b_original: &B, + b: Option, + f: F) + -> Option + where A: ToOwned, + B: ToOwned, + F: FnOnce(A::Owned, B::Owned) -> R { match (a, b) { (Some(a), Some(b)) => Some(f(a, b)), - (Some(a), None) => Some(f(a, b_original.clone())), - (None, Some(b)) => Some(f(a_original.clone(), b)), + (Some(a), None) => Some(f(a, b_original.to_owned())), + (None, Some(b)) => Some(f(a_original.to_owned(), b)), (None, None) => None, } } diff --git a/check/src/kindcheck.rs b/check/src/kindcheck.rs index bd65f34b00..61f2fb9789 100644 --- a/check/src/kindcheck.rs +++ b/check/src/kindcheck.rs @@ -146,12 +146,8 @@ impl<'a> KindCheck<'a> { fn builtin_kind(&self, typ: BuiltinType) -> RcKind { match typ { - BuiltinType::String | - BuiltinType::Byte | - BuiltinType::Char | - BuiltinType::Int | - BuiltinType::Float | - BuiltinType::Unit => self.type_kind(), + BuiltinType::String | BuiltinType::Byte | BuiltinType::Char | BuiltinType::Int | + BuiltinType::Float | BuiltinType::Unit => self.type_kind(), BuiltinType::Array => self.function1_kind(), BuiltinType::Function => self.function2_kind(), } diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index 76c7b9f5ff..c5f2fbd601 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -540,11 +540,11 @@ impl<'a> Typecheck<'a> { op.typ = try!(self.find(op.id())); let func_type = Type::function(vec![lhs_type, rhs_type], self.subs.new_var()); - let ret = - try!(self.unify(&op.typ, func_type)).as_function() - .and_then(|(_, ret)| ret.as_function()) - .map(|(_, ret)| ret.clone()) - .expect("ICE: unify binop"); + let ret = try!(self.unify(&op.typ, func_type)) + .as_function() + .and_then(|(_, ret)| ret.as_function()) + .map(|(_, ret)| ret.clone()) + .expect("ICE: unify binop"); Ok(ret) } @@ -978,9 +978,7 @@ impl<'a> Typecheck<'a> { self.stack_var(args[0].id().clone(), arg.clone()); self.typecheck_pattern_rec(&args[1..], ret.clone()) } - None => { - Err(PatternError(typ.clone(), args.len())) - }, + None => Err(PatternError(typ.clone(), args.len())), } } @@ -1367,4 +1365,3 @@ pub fn unroll_app(typ: &Type) -> Option { Some(Type::app(current.clone(), args)) } } - diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs index 8924e9ee1c..4a25ccebb4 100644 --- a/check/src/unify_type.rs +++ b/check/src/unify_type.rs @@ -149,13 +149,30 @@ fn do_zip_match<'a, 's, U>(self_: &TcType, debug!("Unifying:\n{:?} <=> {:?}", self_, other); match (&**self_, &**other) { (&Type::App(ref l, ref l_args), &Type::App(ref r, ref r_args)) => { - if l_args.len() == r_args.len() { - let ctor = unifier.try_match(l, r); - let args = walk_move_types(l_args.iter().zip(r_args.iter()), - |l, r| unifier.try_match(l, r)); - Ok(merge(l, ctor, l_args, args, Type::app)) - } else { - unify_app(unifier, l, l_args, other) + use std::cmp::Ordering::*; + match l_args.len().cmp(&r_args.len()) { + Equal => { + let new_type = unifier.try_match(l, r); + let new_args = walk_move_types(l_args.iter().zip(r_args), + |l, r| unifier.try_match(l, r)); + Ok(merge(l, new_type, l_args, new_args, Type::app)) + } + Less => { + let offset = r_args.len() - l_args.len(); + let new_type = + unifier.try_match(l, &Type::app(r.clone(), r_args[..offset].into())); + let new_args = walk_move_types(l_args.iter().zip(&r_args[offset..]), + |l, r| unifier.try_match(l, r)); + Ok(merge(l, new_type, l_args, new_args, Type::app)) + } + Greater => { + let offset = l_args.len() - r_args.len(); + let new_type = + unifier.try_match(&Type::app(l.clone(), l_args[..offset].into()), r); + let new_args = walk_move_types(l_args[offset..].iter().zip(r_args), + |l, r| unifier.try_match(l, r)); + Ok(merge(r, new_type, r_args, new_args, Type::app)) + } } } (&Type::Record { fields: ref l_args, types: ref l_types }, @@ -330,77 +347,6 @@ fn try_with_alias<'a, 's, U>(unifier: &mut UnifierState<'a, 's, U>, } } -fn unify_app<'a, 's, U, E>(unifier: &mut UnifierState<'a, 's, U>, - l: &TcType, - l_args: &[TcType], - r: &TcType) - -> Result, E> - where U: Unifier, TcType> -{ - let mut args = Vec::new(); - unify_app_(unifier, l, l_args, r, false, &mut args); - if args.is_empty() { - Ok(None) - } else { - Ok(Some(Type::app(l.clone(), args))) - } -} - -fn unify_app_<'a, 's, U>(unifier: &mut UnifierState<'a, 's, U>, - l: &TcType, - l_args: &[TcType], - r: &TcType, - replaced: bool, - output: &mut Vec) - where U: Unifier, TcType> -{ - let r = unifier.subs.real(r); - let new = match **r { - Type::App(ref r, ref r_args) => { - use std::cmp::Ordering::*; - let args_iter = match l_args.len().cmp(&r_args.len()) { - Equal => { - unifier.try_match(l, r); - l_args.iter().zip(r_args) - } - Less => { - let offset = r_args.len() - l_args.len(); - unifier.try_match(l, &Type::app(r.clone(), r_args[..offset].into())); - l_args.iter().zip(&r_args[offset..]) - } - Greater => { - let offset = l_args.len() - r_args.len(); - unifier.try_match(&Type::app(l.clone(), l_args[..offset].into()), r); - r_args.iter().zip(&l_args[offset..]) - } - }; - // Unify the last min(l_args.len(), r_args.len()) arguments - match walk_move_types(args_iter, |l, r| unifier.try_match(l, r)) { - Some(args) => { - output.extend(args); - return; - } - None => None, - } - } - _ => { - let l = Type::app(l.clone(), l_args.iter().cloned().collect()); - unifier.try_match(&l, r); - // Dont push the actual type that is applied - return; - } - }; - match new { - Some(typ) => { - output.push(typ); - } - None if replaced || !output.is_empty() => { - output.push(r.clone()); - } - None => (), - } -} - fn walk_move_types<'a, I, F, T>(types: I, mut f: F) -> Option> where I: Iterator, F: FnMut(&'a T, &'a T) -> Option, From bf545579341e6d28cee33fe355054a5c565ea008 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 24 Jul 2016 21:49:06 +0200 Subject: [PATCH 2/3] refactor: Implement Display for the unification error types --- check/src/typecheck.rs | 5 ++--- check/src/unify.rs | 19 +++++++++++++++++++ check/src/unify_type.rs | 32 +++++++++++++------------------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index c5f2fbd601..f57d6842a0 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -90,10 +90,9 @@ impl> fmt::Display for TypeError { return Ok(()); } for error in &errors[..errors.len() - 1] { - try!(::unify_type::fmt_error(error, f)); - try!(writeln!(f, "")); + try!(writeln!(f, "{}", error)); } - ::unify_type::fmt_error(errors.last().unwrap(), f) + write!(f, "{}", errors.last().unwrap()) } PatternError(ref typ, expected_len) => { write!(f, "Type {} has {} to few arguments", typ, expected_len) diff --git a/check/src/unify.rs b/check/src/unify.rs index 5c7dfae954..d63f7407ad 100644 --- a/check/src/unify.rs +++ b/check/src/unify.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::fmt; use std::hash::Hash; use base::error::Errors; @@ -12,6 +13,24 @@ pub enum Error { Other(E), } +impl fmt::Display for Error + where T: Substitutable + fmt::Display, + T::Variable: fmt::Display, + E: fmt::Display +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use unify::Error::*; + match *self { + TypeMismatch(ref l, ref r) => { + write!(f, "Types do not match:\n\tExpected: {}\n\tFound: {}", l, r) + } + Occurs(ref var, ref typ) => write!(f, "Variable `{}` occurs in `{}`.", var, typ), + Other(ref err) => write!(f, "{}", err), + } + } +} + + pub struct UnifierState<'s, S: ?Sized + 's, T: 's, U> { pub state: &'s mut S, pub subs: &'s Substitution, diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs index 4a25ccebb4..801cf36402 100644 --- a/check/src/unify_type.rs +++ b/check/src/unify_type.rs @@ -45,31 +45,25 @@ impl From for Error { } } -pub fn fmt_error(error: &Error, f: &mut fmt::Formatter) -> fmt::Result +impl fmt::Display for TypeError where I: fmt::Display + AsRef { - use unify::Error::*; - match *error { - TypeMismatch(ref l, ref r) => { - write!(f, "Types do not match:\n\tExpected: {}\n\tFound: {}", l, r) - } - Other(TypeError::FieldMismatch(ref l, ref r)) => { - write!(f, - "Field names in record do not match.\n\tExpected: {}\n\tFound: {}", - l, - r) - } - Occurs(ref var, ref typ) => write!(f, "Variable `{}` occurs in `{}`.", var, typ), - Other(TypeError::UndefinedType(ref id)) => write!(f, "Type `{}` does not exist.", id), - Other(TypeError::SelfRecursive(ref id)) => { - write!(f, - "The use of self recursion in type `{}` could not be unified.", - id) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TypeError::FieldMismatch(ref l, ref r) => { + write!(f, + "Field names in record do not match.\n\tExpected: {}\n\tFound: {}", + l, + r) + } + TypeError::UndefinedType(ref id) => write!(f, "Type `{}` does not exist.", id), + TypeError::SelfRecursive(ref id) => { + write!(f, "The use of self recursion in type `{}` could not be unified.", id) + } } } } - pub type UnifierState<'a, 's, U> = unify::UnifierState<'s, State<'a>, TcType, U>; impl Variable for TypeVariable { From 89ab4ee2c66972cc4d4caf8f486b4d252962170f Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 24 Jul 2016 22:50:48 +0200 Subject: [PATCH 3/3] style: Run clippy on the check crate --- check/src/completion.rs | 61 ++++---- check/src/kindcheck.rs | 2 +- check/src/rename.rs | 4 +- check/src/typecheck.rs | 325 ++++++++++++++++++++-------------------- check/src/unify_type.rs | 4 +- 5 files changed, 197 insertions(+), 199 deletions(-) diff --git a/check/src/completion.rs b/check/src/completion.rs index 66e2dca392..aac4e9c54c 100644 --- a/check/src/completion.rs +++ b/check/src/completion.rs @@ -48,15 +48,13 @@ impl OnFound for Suggest { fn on_pattern(&mut self, pattern: &ast::LPattern>) { match pattern.value { - ast::Pattern::Record { ref id, ref fields, .. } => { - match *instantiate::remove_aliases(&(), id.typ.clone()) { - Type::Record { fields: ref field_types, .. } => { - for (field, field_type) in fields.iter().zip(field_types) { - let f = field.1.as_ref().unwrap_or(&field.0).clone(); - self.stack.insert(f, field_type.typ.clone()); - } + ast::Pattern::Record { ref id, fields: ref field_ids, .. } => { + let unaliased = instantiate::remove_aliases(&(), id.typ.clone()); + if let Type::Record { ref fields, .. } = *unaliased { + for (field, field_type) in field_ids.iter().zip(fields) { + let f = field.1.as_ref().unwrap_or(&field.0).clone(); + self.stack.insert(f, field_type.typ.clone()); } - _ => (), } } ast::Pattern::Identifier(ref id) => { @@ -71,41 +69,32 @@ impl OnFound for Suggest { } fn expr(&mut self, expr: &ast::LExpr>) { - match expr.value { - ast::Expr::Identifier(ref ident) => { - for (k, typ) in self.stack.iter() { - if k.declared_name().starts_with(ident.name.declared_name()) { - self.result.push(ast::TcIdent { - name: k.clone(), - typ: typ.clone(), - }); - } + if let ast::Expr::Identifier(ref ident) = expr.value { + for (k, typ) in self.stack.iter() { + if k.declared_name().starts_with(ident.name.declared_name()) { + self.result.push(ast::TcIdent { + name: k.clone(), + typ: typ.clone(), + }); } } - _ => (), } } fn ident(&mut self, context: &ast::LExpr>, ident: &ast::TcIdent) { - match context.value { - ast::Expr::FieldAccess(ref expr, _) => { - let typ = expr.type_of(); - match *instantiate::remove_aliases(&(), typ) { - Type::Record { ref fields, .. } => { - let id = ident.name.as_ref(); - for field in fields { - if field.name.as_ref().starts_with(id) { - self.result.push(ast::TcIdent { - name: field.name.clone(), - typ: field.typ.clone(), - }); - } - } + if let ast::Expr::FieldAccess(ref expr, _) = context.value { + let typ = expr.type_of(); + if let Type::Record { ref fields, .. } = *instantiate::remove_aliases(&(), typ) { + let id = ident.name.as_ref(); + for field in fields { + if field.name.as_ref().starts_with(id) { + self.result.push(ast::TcIdent { + name: field.name.clone(), + typ: field.typ.clone(), + }); } - _ => (), } } - _ => (), } } } @@ -189,7 +178,7 @@ impl<'a, F> FindVisitor<'a, F> match self.select_spanned(bindings, |b| b.expression.span(self.env)) { (false, Some(bind)) => { for arg in &bind.arguments { - self.on_found.on_ident(&arg); + self.on_found.on_ident(arg); } self.visit_expr(&bind.expression) } @@ -213,7 +202,7 @@ impl<'a, F> FindVisitor<'a, F> } Lambda(ref lambda) => { for arg in &lambda.arguments { - self.on_found.on_ident(&arg); + self.on_found.on_ident(arg); } self.visit_expr(&lambda.body) } diff --git a/check/src/kindcheck.rs b/check/src/kindcheck.rs index 61f2fb9789..c05e068455 100644 --- a/check/src/kindcheck.rs +++ b/check/src/kindcheck.rs @@ -115,7 +115,7 @@ impl<'a> KindCheck<'a> { }) .or_else(|| self.info.find_kind(id)) .map_or_else(|| { - let id_str = self.idents.string(&id); + let id_str = self.idents.string(id); if id_str.chars().next().map_or(false, |c| c.is_uppercase()) { Err(UnifyError::Other(KindError::UndefinedType(id.clone()))) } else { diff --git a/check/src/rename.rs b/check/src/rename.rs index 9688b73bdc..49b6defc91 100644 --- a/check/src/rename.rs +++ b/check/src/rename.rs @@ -165,13 +165,13 @@ pub fn rename(symbols: &mut SymbolModule, let locals = self.env .stack .get_all(id); - let global = self.env.env.find_type(&id).map(|typ| (id, None, typ)); + let global = self.env.env.find_type(id).map(|typ| (id, None, typ)); let candidates = || { locals.iter() .flat_map(|bindings| { bindings.iter().rev().map(|bind| (&bind.0, Some(&bind.1), &bind.2)) }) - .chain(global.clone()) + .chain(global) }; // If there is a single binding (or no binding in case of primitives such as #Int+) // there is no need to check for equivalency as typechecker couldnt have infered a diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index f57d6842a0..1d7f13f359 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -257,7 +257,7 @@ impl<'a> Typecheck<'a> { let subs = &mut self.subs; let inst = &mut self.inst; self.environment - .find_type(&id) + .find_type(id) .ok_or_else(|| UndefinedVariable(id.clone())) .map(|typ| { let typ = subs.set_type(typ.clone()); @@ -504,26 +504,12 @@ impl<'a> Typecheck<'a> { let result = if op_name.starts_with('#') { // Handle primitives let arg_type = try!(self.unify(&lhs_type, rhs_type)); - let offset; - let prim_type: TcType = if op_name[1..].starts_with("Int") { - offset = "Int".len(); - Type::int() - } else if op_name[1..].starts_with("Float") { - offset = "Float".len(); - Type::float() - } else if op_name[1..].starts_with("Char") { - offset = "Char".len(); - Type::char() - } else if op_name[1..].starts_with("Byte") { - offset = "Byte".len(); - Type::byte() - } else { - panic!("ICE: Unknown primitive type") - }; + let op_type = op_name.trim_matches(|c: char| !c.is_alphabetic()); + let prim_type = primitive_type(op_type); op.typ = Type::function(vec![prim_type.clone(), prim_type.clone()], prim_type.clone()); let typ = try!(self.unify(&prim_type, arg_type)); - match &op_name[1 + offset..] { + match &op_name[1 + op_type.len()..] { "+" | "-" | "*" | "/" => Ok(typ), "==" | "<" => Ok(self.bool()), _ => Err(UndefinedVariable(op.name.clone())), @@ -574,74 +560,7 @@ impl<'a> Typecheck<'a> { .map(TailCall::Type) } ast::Expr::Let(ref mut bindings, _) => { - self.enter_scope(); - let level = self.subs.var_id(); - let is_recursive = bindings.iter().all(|bind| !bind.arguments.is_empty()); - // When the decfinitions are allowed to be mutually recursive - if is_recursive { - for bind in bindings.iter_mut() { - let mut typ = self.subs.new_var(); - if let Some(ref mut type_decl) = bind.typ { - *type_decl = self.refresh_symbols_in_type(type_decl.clone()); - try!(self.kindcheck(type_decl, &mut [])); - let decl = self.instantiate(type_decl); - typ = self.unify_span(bind.name.span(), &decl, typ); - } - self.typecheck_pattern(&mut bind.name, typ); - if let ast::Expr::Lambda(ref mut lambda) = bind.expression.value { - if let ast::Pattern::Identifier(ref name) = bind.name.value { - lambda.id.name = name.name.clone(); - } - } - } - } - let mut types = Vec::new(); - for bind in bindings.iter_mut() { - // Functions which are declared as `let f x = ...` are allowed to be self - // recursive - let mut typ = if bind.arguments.is_empty() { - if let Some(ref mut type_decl) = bind.typ { - *type_decl = self.refresh_symbols_in_type(type_decl.clone()); - try!(self.kindcheck(type_decl, &mut [])); - } - self.typecheck(&mut bind.expression) - } else { - let function_type = match bind.typ { - Some(ref typ) => self.instantiate(typ), - None => self.subs.new_var(), - }; - self.typecheck_lambda(function_type, - &mut bind.arguments, - &mut bind.expression) - }; - debug!("let {:?} : {}", - bind.name, - types::display_type(&self.symbols, &typ)); - if let Some(ref type_decl) = bind.typ { - typ = self.unify_span(bind.name.span(), type_decl, typ); - } - if !is_recursive { - // Merge the type declaration and the actual type - self.generalize_variables(level, &mut bind.expression); - self.typecheck_pattern(&mut bind.name, typ); - } else { - types.push(typ); - } - } - if is_recursive { - for (typ, bind) in types.into_iter().zip(bindings.iter_mut()) { - // Merge the variable we bound to the name and the type inferred - // in the expression - self.unify_span(bind.name.span(), &bind.type_of().clone(), typ); - } - } - // Once all variables inside the let has been unified we can quantify them - debug!("Generalize {}", level); - for bind in bindings { - self.generalize_variables(level, &mut bind.expression); - self.finish_binding(level, bind); - } - debug!("Typecheck `in`"); + try!(self.typecheck_bindings(bindings)); Ok(TailCall::TailCall) } ast::Expr::FieldAccess(ref mut expr, ref mut field_access) => { @@ -695,77 +614,7 @@ impl<'a> Typecheck<'a> { Ok(TailCall::Type(typ)) } ast::Expr::Type(ref mut bindings, ref expr) => { - self.enter_scope(); - // Rename the types so they get a name which is distinct from types from other - // modules - for bind in bindings.iter_mut() { - let s = String::from(self.symbols.string(&bind.alias.name)); - let new = self.symbols.scoped_symbol(&s); - self.original_symbols.insert(bind.alias.name.clone(), new.clone()); - // Rename the aliase's name to its global name - Alias::make_mut(&mut bind.alias).name = new; - } - for bind in bindings.iter_mut() { - let typ = Alias::make_mut(&mut bind.alias) - .typ - .as_mut() - .expect("Expected binding to have an aliased type"); - *typ = self.refresh_symbols_in_type(typ.clone()); - } - { - let subs = Substitution::new(); - let mut check = KindCheck::new(&self.environment, &self.symbols, subs); - // Setup kind variables for all type variables and insert the types in the - // this type expression into the kindcheck environment - for bind in bindings.iter_mut() { - // Create the kind for this binding - // Test a b: 2 -> 1 -> Type - // and bind the same variables to the arguments of the type binding - // ('a' and 'b' in the example) - let mut id_kind = check.type_kind(); - let alias = Alias::make_mut(&mut bind.alias); - for gen in alias.args.iter_mut().rev() { - gen.kind = check.subs.new_var(); - id_kind = Kind::function(gen.kind.clone(), id_kind); - } - check.add_local(alias.name.clone(), id_kind); - } - - // Kindcheck all the types in the environment - for bind in bindings.iter_mut() { - check.set_variables(&bind.alias.args); - let typ = Alias::make_mut(&mut bind.alias) - .typ - .as_mut() - .expect("Expected binding to have an aliased type"); - try!(check.kindcheck_type(typ)); - } - - // All kinds are now inferred so replace the kinds store in the AST - for bind in bindings.iter_mut() { - let alias = Alias::make_mut(&mut bind.alias); - if let Some(ref mut typ) = alias.typ { - *typ = check.finalize_type(typ.clone()); - } - for arg in &mut alias.args { - *arg = check.finalize_generic(&arg); - } - } - } - - // Finally insert the declared types into the global scope - for bind in bindings { - let args = &bind.alias.args; - debug!("HELP {} \n{:?}", self.symbols.string(&bind.name), args); - if self.environment.stack_types.get(&bind.name).is_some() { - self.errors.error(ast::Spanned { - span: expr.span(&ast::TcIdentEnvWrapper(&self.symbols)), - value: DuplicateTypeDefinition(bind.name.clone()), - }); - } else { - self.stack_type(bind.name.clone(), &bind.alias); - } - } + try!(self.typecheck_type_bindings(bindings, expr)); Ok(TailCall::TailCall) } ast::Expr::Record { typ: ref mut id, ref mut types, exprs: ref mut fields } => { @@ -981,6 +830,154 @@ impl<'a> Typecheck<'a> { } } + fn typecheck_bindings(&mut self, bindings: &mut [ast::Binding]) -> TcResult<()> { + self.enter_scope(); + let level = self.subs.var_id(); + let is_recursive = bindings.iter().all(|bind| !bind.arguments.is_empty()); + // When the decfinitions are allowed to be mutually recursive + if is_recursive { + for bind in bindings.iter_mut() { + let mut typ = self.subs.new_var(); + if let Some(ref mut type_decl) = bind.typ { + *type_decl = self.refresh_symbols_in_type(type_decl.clone()); + try!(self.kindcheck(type_decl, &mut [])); + let decl = self.instantiate(type_decl); + typ = self.unify_span(bind.name.span(), &decl, typ); + } + self.typecheck_pattern(&mut bind.name, typ); + if let ast::Expr::Lambda(ref mut lambda) = bind.expression.value { + if let ast::Pattern::Identifier(ref name) = bind.name.value { + lambda.id.name = name.name.clone(); + } + } + } + } + let mut types = Vec::new(); + for bind in bindings.iter_mut() { + // Functions which are declared as `let f x = ...` are allowed to be self + // recursive + let mut typ = if bind.arguments.is_empty() { + if let Some(ref mut type_decl) = bind.typ { + *type_decl = self.refresh_symbols_in_type(type_decl.clone()); + try!(self.kindcheck(type_decl, &mut [])); + } + self.typecheck(&mut bind.expression) + } else { + let function_type = match bind.typ { + Some(ref typ) => self.instantiate(typ), + None => self.subs.new_var(), + }; + self.typecheck_lambda(function_type, &mut bind.arguments, &mut bind.expression) + }; + debug!("let {:?} : {}", + bind.name, + types::display_type(&self.symbols, &typ)); + if let Some(ref type_decl) = bind.typ { + typ = self.unify_span(bind.name.span(), type_decl, typ); + } + if !is_recursive { + // Merge the type declaration and the actual type + self.generalize_variables(level, &mut bind.expression); + self.typecheck_pattern(&mut bind.name, typ); + } else { + types.push(typ); + } + } + if is_recursive { + for (typ, bind) in types.into_iter().zip(bindings.iter_mut()) { + // Merge the variable we bound to the name and the type inferred + // in the expression + self.unify_span(bind.name.span(), &bind.type_of().clone(), typ); + } + } + // Once all variables inside the let has been unified we can quantify them + debug!("Generalize {}", level); + for bind in bindings { + self.generalize_variables(level, &mut bind.expression); + self.finish_binding(level, bind); + } + debug!("Typecheck `in`"); + Ok(()) + } + + fn typecheck_type_bindings(&mut self, + bindings: &mut [ast::TypeBinding], + expr: &ast::LExpr) + -> TcResult<()> { + self.enter_scope(); + // Rename the types so they get a name which is distinct from types from other + // modules + for bind in bindings.iter_mut() { + let s = String::from(self.symbols.string(&bind.alias.name)); + let new = self.symbols.scoped_symbol(&s); + self.original_symbols.insert(bind.alias.name.clone(), new.clone()); + // Rename the aliase's name to its global name + Alias::make_mut(&mut bind.alias).name = new; + } + for bind in bindings.iter_mut() { + let typ = Alias::make_mut(&mut bind.alias) + .typ + .as_mut() + .expect("Expected binding to have an aliased type"); + *typ = self.refresh_symbols_in_type(typ.clone()); + } + { + let subs = Substitution::new(); + let mut check = KindCheck::new(&self.environment, &self.symbols, subs); + // Setup kind variables for all type variables and insert the types in the + // this type expression into the kindcheck environment + for bind in bindings.iter_mut() { + // Create the kind for this binding + // Test a b: 2 -> 1 -> Type + // and bind the same variables to the arguments of the type binding + // ('a' and 'b' in the example) + let mut id_kind = check.type_kind(); + let alias = Alias::make_mut(&mut bind.alias); + for gen in alias.args.iter_mut().rev() { + gen.kind = check.subs.new_var(); + id_kind = Kind::function(gen.kind.clone(), id_kind); + } + check.add_local(alias.name.clone(), id_kind); + } + + // Kindcheck all the types in the environment + for bind in bindings.iter_mut() { + check.set_variables(&bind.alias.args); + let typ = Alias::make_mut(&mut bind.alias) + .typ + .as_mut() + .expect("Expected binding to have an aliased type"); + try!(check.kindcheck_type(typ)); + } + + // All kinds are now inferred so replace the kinds store in the AST + for bind in bindings.iter_mut() { + let alias = Alias::make_mut(&mut bind.alias); + if let Some(ref mut typ) = alias.typ { + *typ = check.finalize_type(typ.clone()); + } + for arg in &mut alias.args { + *arg = check.finalize_generic(&arg); + } + } + } + + // Finally insert the declared types into the global scope + for bind in bindings { + let args = &bind.alias.args; + debug!("HELP {} \n{:?}", self.symbols.string(&bind.name), args); + if self.environment.stack_types.get(&bind.name).is_some() { + self.errors.error(ast::Spanned { + span: expr.span(&ast::TcIdentEnvWrapper(&self.symbols)), + value: DuplicateTypeDefinition(bind.name.clone()), + }); + } else { + self.stack_type(bind.name.clone(), &bind.alias); + } + } + Ok(()) + } + fn kindcheck(&self, typ: &mut TcType, args: &mut [Generic]) -> TcResult<()> { let subs = Substitution::new(); let mut check = super::kindcheck::KindCheck::new(&self.environment, &self.symbols, subs); @@ -1037,7 +1034,7 @@ impl<'a> Typecheck<'a> { } } if let Some(typ) = typ { - *self.environment.stack.get_mut(&symbol).unwrap() = self.finish_type(level, typ); + *self.environment.stack.get_mut(symbol).unwrap() = self.finish_type(level, typ); } } @@ -1047,7 +1044,7 @@ impl<'a> Typecheck<'a> { let vars = self.inst.named_variables.borrow(); let max_var = vars.keys() .fold("a", - |max, current| ::std::cmp::max(max, self.symbols.string(¤t))); + |max, current| ::std::cmp::max(max, self.symbols.string(current))); String::from(max_var) }; let mut i = 0; @@ -1315,6 +1312,16 @@ fn function_arg_iter<'a, 'b>(tc: &'a mut Typecheck<'b>, typ: TcType) -> Function FunctionArgIter { tc: tc, typ: typ } } +fn primitive_type(op_type: &str) -> TcType { + match op_type { + "Int" => Type::int(), + "Float" => Type::float(), + "Char" => Type::char(), + "Byte" => Type::byte(), + _ => panic!("ICE: Unknown primitive type"), + } +} + /// Removes layers of `Type::App`. /// /// Example: diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs index 801cf36402..07ad09b5c1 100644 --- a/check/src/unify_type.rs +++ b/check/src/unify_type.rs @@ -58,7 +58,9 @@ impl fmt::Display for TypeError } TypeError::UndefinedType(ref id) => write!(f, "Type `{}` does not exist.", id), TypeError::SelfRecursive(ref id) => { - write!(f, "The use of self recursion in type `{}` could not be unified.", id) + write!(f, + "The use of self recursion in type `{}` could not be unified.", + id) } } }