Skip to content

Commit

Permalink
Merge pull request #125 from brendanzab/holes
Browse files Browse the repository at this point in the history
Add holes to the type syntax, and use them when building the AST
  • Loading branch information
brendanzab committed Aug 22, 2016
2 parents 10dd3f9 + e1adff6 commit 55e93ac
Show file tree
Hide file tree
Showing 9 changed files with 31 additions and 24 deletions.
1 change: 1 addition & 0 deletions base/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ fn walk_move_type2<F, I, T>(typ: &Type<I, T>, f: &mut F) -> Option<T>
|v| walk_move_type2(&v.1, f).map(|t| (v.0.clone(), t)))
.map(Type::variants)
}
Type::Hole |
Type::Builtin(_) |
Type::Variable(_) |
Type::Generic(_) |
Expand Down
11 changes: 10 additions & 1 deletion base/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ pub fn instantiate<F>(typ: TcType, mut f: F) -> TcType
/// the pointer wrapper directly.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Type<Id, T = AstType<Id>> {
/// An unbound type `_`, awaiting ascription.
Hole,
/// An application with multiple arguments.
/// `Map String Int` would be represented as `App(Map, [String, Int])`
App(T, Vec<T>),
Expand All @@ -107,7 +109,7 @@ pub enum Type<Id, T = AstType<Id>> {
/// The fields of this record type
fields: Vec<Field<Id, T>>,
},
/// An identifier type. Anything which is not a builting type.
/// An identifier type. Anything that is not a builtin type.
Id(Id),
Alias(AliasData<Id, T>),
}
Expand Down Expand Up @@ -419,6 +421,10 @@ pub struct Field<Id, T = AstType<Id>> {
impl<Id, T> Type<Id, T>
where T: From<Type<Id, T>>
{
pub fn hole() -> T {
T::from(Type::Hole)
}

pub fn array(typ: T) -> T {
Type::app(Type::builtin(BuiltinType::Array), vec![typ])
}
Expand Down Expand Up @@ -734,6 +740,7 @@ impl<'a, I, T, E> DisplayType<'a, I, T, E>
{
let p = self.prec;
match *self.typ {
Type::Hole => arena.text("_"),
Type::Variable(ref var) => arena.text(format!("{}", var.id)),
Type::Generic(ref gen) => arena.text(gen.id.as_ref()),
Type::App(ref t, ref args) => {
Expand Down Expand Up @@ -892,6 +899,7 @@ pub fn walk_type_<I, T, F: ?Sized>(typ: &T, f: &mut F)
f.walk(&variant.1);
}
}
Type::Hole |
Type::Builtin(_) |
Type::Variable(_) |
Type::Generic(_) |
Expand Down Expand Up @@ -1037,6 +1045,7 @@ pub fn walk_move_type_opt<F: ?Sized, I, T>(typ: &Type<I, T>, f: &mut F) -> Optio
walk_move_types(variants, |v| f.visit(&v.1).map(|t| (v.0.clone(), t)))
.map(Type::variants)
}
Type::Hole |
Type::Builtin(_) |
Type::Variable(_) |
Type::Generic(_) |
Expand Down
1 change: 1 addition & 0 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl<'a> KindCheck<'a> {

fn kindcheck(&mut self, typ: &TcType) -> Result<(RcKind, TcType)> {
match **typ {
Type::Hole => Ok((self.subs.new_var(), typ.clone())),
Type::Generic(ref gen) => {
let mut gen = gen.clone();
gen.kind = try!(self.find(&gen.id));
Expand Down
18 changes: 7 additions & 11 deletions check/src/substitution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,27 +161,22 @@ impl<T: fmt::Debug> fmt::Debug for Substitution<T> {

impl<T> Substitution<T> {
pub fn var_id(&self) -> u32 {
(self.variables.borrow().len() - 1) as u32
self.variables.borrow().len() as u32
}
}

impl<T: Substitutable> Substitution<T> {
pub fn new() -> Substitution<T> {
let variables = FixedVec::new();
// 0 is the default, uninitialized variable so we add it to make sure that the first
// variable we create through `new_var` is 1
variables.push(T::new(0));
Substitution {
union: RefCell::new(QuickFindUf::new(1)),
variables: variables,
union: RefCell::new(QuickFindUf::new(0)),
variables: FixedVec::new(),
types: FixedMap::new(),
}
}

pub fn clear(&mut self) {
self.types.clear();
self.variables.clear();
self.variables.push(T::new(0));
}

pub fn insert(&self, var: u32, t: T) {
Expand All @@ -206,9 +201,10 @@ impl<T: Substitutable> Substitution<T> {
let var_id = self.variables.len() as u32;
let id = self.union.borrow_mut().insert(UnionByLevel::default());
assert!(id == self.variables.len());
self.variables.push(T::new(var_id));
let last = self.variables.len() - 1;
self.variables[last].clone()

let var = T::new(var_id);
self.variables.push(var.clone());
var
}

/// If `typ` is a variable this returns the real unified value of that variable. Otherwise it
Expand Down
2 changes: 1 addition & 1 deletion check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ impl<'a> Typecheck<'a> {
typ = &**t;
}
match *typ {
Type::Variable(ref var) if self.subs.get_level(var.id) > level => {
Type::Variable(ref var) if self.subs.get_level(var.id) >= level => {
// Create a prefix if none exists
if generic.is_none() {
let mut g = String::new();
Expand Down
11 changes: 6 additions & 5 deletions check/src/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,12 @@ mod test {
}));
}

fn intersection(subs: &Substitution<TType>, l: &TType, r: &TType) -> TType {
super::intersection(subs, (), l, r)
}
#[test]
fn intersection_test() {
fn intersection(subs: &Substitution<TType>, l: &TType, r: &TType) -> TType {
super::intersection(subs, (), l, r)
}

let subs = Substitution::<TType>::new();
let var1 = subs.new_var();
let string = TType(Box::new(Type::Id("String".into())));
Expand All @@ -371,10 +372,10 @@ mod test {
let string_fun = mk_fn(&string, &string);
let int_fun = mk_fn(&int, &int);
let result = intersection(&subs, &int_fun, &string_fun);
assert_eq!(result, mk_fn(&TType::new(2), &TType::new(2)));
assert_eq!(result, mk_fn(&TType::new(1), &TType::new(1)));

let var_fun = mk_fn(&var1, &var1);
let result = intersection(&subs, &int_fun, &var_fun);
assert_eq!(result, mk_fn(&TType::new(3), &TType::new(3)));
assert_eq!(result, mk_fn(&TType::new(2), &TType::new(2)));
}
}
2 changes: 1 addition & 1 deletion parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fmt;
use base::pos::{BytePos, CharPos, Location, Span, Spanned};

use combine::primitives::{Consumed, Error as CombineError, RangeStream};
use combine::combinator::{range, take, take_while, EnvParser};
use combine::combinator::{take, take_while, EnvParser};
use combine::*;
use combine::char::{alpha_num, char, letter, spaces, string};
use combine_language::{LanguageEnv, LanguageDef, Identifier};
Expand Down
7 changes: 2 additions & 5 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use base::ast;
use base::ast::*;
use base::error::Errors;
use base::pos::{self, Location, Located, Span};
use base::types::{Type, Generic, Alias, Field, Kind, TypeVariable};
use base::types::{Type, Generic, Alias, Field, Kind};
use base::symbol::{Name, Symbol, SymbolModule};

use combine::primitives::{Consumed, Stream, StreamOnce, Error as CombineError, Info,
Expand Down Expand Up @@ -805,10 +805,7 @@ pub fn parse_tc
input: &str)
-> Result<SpannedExpr<TcIdent<Symbol>>, (Option<SpannedExpr<TcIdent<Symbol>>>, Errors<Error>)> {
let mut env = ast::TcIdentEnv {
typ: Type::variable(TypeVariable {
id: 0,
kind: Kind::typ(),
}),
typ: Type::hole(),
env: symbols,
};
parse_expr(&mut env, input)
Expand Down
2 changes: 2 additions & 0 deletions parser/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ y
#[test]
fn expression() {
let _ = ::env_logger::init();
let e = parse("2 * 3 + 4");
assert_eq!(e, Ok(binop(binop(int(2), "*", int(3)), "+", int(4))));
let e = parse(r#"\x y -> x + y"#);
assert_eq!(e,
Ok(lambda("",
Expand Down

0 comments on commit 55e93ac

Please sign in to comment.