Skip to content

Commit

Permalink
Merge pull request #606 from Marwes/forall_escape
Browse files Browse the repository at this point in the history
Issue 599
  • Loading branch information
Marwes authored Aug 23, 2018
2 parents d31a1f8 + f7ffc70 commit 2562070
Show file tree
Hide file tree
Showing 17 changed files with 483 additions and 157 deletions.
2 changes: 1 addition & 1 deletion base/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ pub fn walk_mut_ast_type<'a, V: ?Sized + MutVisitor<'a>>(
s: &'a mut SpannedAstType<V::Ident>,
) {
match s.value {
Type::Hole | Type::Opaque | Type::Builtin(_) => (),
Type::Hole | Type::Opaque | Type::Error | Type::Builtin(_) => (),
Type::Forall(_, ref mut ast_type, ref mut ast_types) => {
v.visit_ast_type(&mut ast_type._typ.1);
if let &mut Some(ref mut ast_types) = ast_types {
Expand Down
10 changes: 8 additions & 2 deletions base/src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl KindEnv for EmptyEnv<Symbol> {
)]
pub enum Kind {
Hole,
Error,
/// Representation for a kind which is yet to be inferred.
Variable(u32),
/// The simplest possible kind. All values in a program have this kind.
Expand All @@ -68,6 +69,10 @@ impl Kind {
ArcKind::new(Kind::Hole)
}

pub fn error() -> ArcKind {
ArcKind::new(Kind::Error)
}

pub fn variable(v: u32) -> ArcKind {
ArcKind::new(Kind::Variable(v))
}
Expand Down Expand Up @@ -115,6 +120,7 @@ impl<'a> fmt::Display for DisplayKind<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.1 {
Kind::Hole => "_".fmt(f),
Kind::Error => "!".fmt(f),
Kind::Variable(i) => i.fmt(f),
Kind::Type => "Type".fmt(f),
Kind::Row => "Row".fmt(f),
Expand Down Expand Up @@ -186,7 +192,7 @@ impl fmt::Display for ArcKind {
}
}

type_cache! { KindCache() () { ArcKind, Kind } row hole typ }
type_cache! { KindCache() () { ArcKind, Kind } row hole error typ }

impl<'a, F: ?Sized> Walker<'a, ArcKind> for F
where
Expand All @@ -207,6 +213,6 @@ where
f.walk(a);
f.walk(r);
}
Kind::Hole | Kind::Variable(_) | Kind::Type | Kind::Row => (),
Kind::Hole | Kind::Error | Kind::Variable(_) | Kind::Type | Kind::Row => (),
}
}
64 changes: 43 additions & 21 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type_cache! {
TypeCache(Id, T)
(kind_cache: ::kind::KindCache)
{ T, Type }
hole opaque int byte float string char
hole opaque error int byte float string char
function_builtin array_builtin unit empty_row
}

Expand Down Expand Up @@ -114,8 +114,7 @@ where
.map(|(i, typ)| Field {
name: symbols.from_str(&format!("_{}", i)),
typ: typ,
})
.collect();
}).collect();
if fields.is_empty() {
self.unit()
} else {
Expand Down Expand Up @@ -388,8 +387,7 @@ where
group: group.clone(),
})),
_marker: PhantomData,
})
.collect()
}).collect()
}

pub fn as_type(&self) -> &T {
Expand Down Expand Up @@ -486,14 +484,16 @@ where
Type::Ident(ref id) => {
// Replace `Ident` with the alias it resolves to so that a `TypeEnv` is not
// needed to resolve the type later on
let replacement = self.group.iter().position(|alias| alias.name == *id).map(
|index| {
T::from(Type::Alias(AliasRef {
index: index,
group: self.group.clone(),
}))
},
);
let replacement =
self.group
.iter()
.position(|alias| alias.name == *id)
.map(|index| {
T::from(Type::Alias(AliasRef {
index: index,
group: self.group.clone(),
}))
});
if replacement.is_none() {
info!("Alias group were not able to resolve an identifier");
}
Expand Down Expand Up @@ -694,6 +694,8 @@ pub enum Type<Id, T = ArcType<Id>> {
Hole,
/// An opaque type
Opaque,
/// A type used to mark type errors
Error,
/// A builtin type
Builtin(BuiltinType),
/// Universally quantified types
Expand Down Expand Up @@ -774,6 +776,10 @@ where
T::from(Type::Opaque)
}

pub fn error() -> T {
T::from(Type::Error)
}

pub fn builtin(typ: BuiltinType) -> T {
T::from(Type::Builtin(typ))
}
Expand Down Expand Up @@ -838,8 +844,7 @@ where
.map(|(i, typ)| Field {
name: symbols.from_str(&format!("_{}", i)),
typ: typ,
})
.collect(),
}).collect(),
Type::empty_row(),
))
}
Expand Down Expand Up @@ -1036,6 +1041,7 @@ where
let mut immediate_kind = match *self {
Type::Function(_, _, _) => Cow::Owned(Kind::typ()),
Type::App(ref t, ref args) => t.kind_(args.len()),
Type::Error => Cow::Owned(Kind::error()),
Type::Hole | Type::Opaque | Type::Builtin(_) | Type::Record(_) | Type::Variant(_) => {
Cow::Owned(Kind::typ())
}
Expand Down Expand Up @@ -1264,6 +1270,20 @@ impl<Id> ArcType<Id> {
{
match **self {
Type::Generic(ref generic) => named_variables.get(&generic.id).cloned(),
Type::Forall(ref params, ref typ, ref vars) => {
let removed: AppVec<_> = params
.iter()
.flat_map(|param| named_variables.remove_entry(&param.id))
.collect();

let new_typ = typ.skolemize_(named_variables);
let new_typ =
new_typ.map(|typ| Type::forall_with_vars(params.clone(), typ, vars.clone()));

named_variables.extend(removed);

new_typ
}
_ => walk_move_type_opt(
self,
&mut ControlVisitation(|typ: &ArcType<Id>| typ.skolemize_(named_variables)),
Expand Down Expand Up @@ -1418,8 +1438,7 @@ impl ArcType {
.take_while(|&(l, r)| match **l {
Type::Generic(ref g) => g == r,
_ => false,
})
.count();
}).count();

let typ = if params.len() <= allowed_missing_args + args.len() {
// Remove the args at the end of the aliased type
Expand Down Expand Up @@ -1881,6 +1900,7 @@ where

let doc = match **typ {
Type::Hole => arena.text("_"),
Type::Error => arena.text("!"),
Type::Opaque => arena.text("<opaque>"),
Type::Forall(ref args, ref typ, _) => {
let doc = chain![arena;
Expand Down Expand Up @@ -2258,6 +2278,7 @@ where
}
Type::Hole
| Type::Opaque
| Type::Error
| Type::Builtin(_)
| Type::Variable(_)
| Type::Generic(_)
Expand Down Expand Up @@ -2304,6 +2325,7 @@ where
}
Type::Hole
| Type::Opaque
| Type::Error
| Type::Builtin(_)
| Type::Variable(_)
| Type::Generic(_)
Expand Down Expand Up @@ -2467,6 +2489,7 @@ where
}
Type::Hole
| Type::Opaque
| Type::Error
| Type::Builtin(_)
| Type::Variable(_)
| Type::Skolem(_)
Expand Down Expand Up @@ -2571,19 +2594,18 @@ where
.map(|field| Field {
name: field.name.clone(),
typ: Alias::from(translate_alias(&field.typ, &mut translate)),
})
.collect(),
}).collect(),
fields
.iter()
.map(|field| Field {
name: field.name.clone(),
typ: translate(&field.typ),
})
.collect(),
}).collect(),
translate(rest),
),
Type::Hole => cache.hole(),
Type::Opaque => cache.opaque(),
Type::Error => cache.error(),
Type::Builtin(ref builtin) => cache.builtin_type(builtin.clone()),
Type::Variable(ref var) => Type::variable(var.clone()),
Type::Generic(ref gen) => Type::generic(gen.clone()),
Expand Down
3 changes: 2 additions & 1 deletion check/src/implicits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ impl<'a, 'b> ResolveImplicitsVisitor<'a, 'b> {
constraint,
}));

let state = ::unify_type::State::new(&self.tc.environment, &self.tc.subs);
let state =
::unify_type::State::new(&self.tc.environment, &self.tc.subs, &self.tc.type_cache);
::unify_type::subsumes(
&self.tc.subs,
&mut ScopedMap::new(),
Expand Down
19 changes: 13 additions & 6 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ where
let ret_new = walk_move_kind2(ret, f);
merge::merge(arg, arg_new, ret, ret_new, Kind::function)
}
Kind::Hole | Kind::Type | Kind::Variable(_) | Kind::Row => None,
Kind::Hole | Kind::Error | Kind::Type | Kind::Variable(_) | Kind::Row => None,
}
};
new2.or(new)
Expand Down Expand Up @@ -115,7 +115,7 @@ impl<'a> KindCheck<'a> {
self.instantiate_kinds(rhs);
return;
}
Kind::Row | Kind::Type => return,
Kind::Row | Kind::Error | Kind::Type => return,
}
*kind = self.subs.new_var();
}
Expand Down Expand Up @@ -191,6 +191,7 @@ impl<'a> KindCheck<'a> {
fn kindcheck(&mut self, typ: &mut AstType<Symbol>) -> Result<ArcKind> {
let span = typ.span();
match **typ {
Type::Error => Ok(self.kind_cache.error()),
Type::Hole | Type::Opaque | Type::Variable(_) => Ok(self.subs.new_var()),
Type::Skolem(ref mut skolem) => {
skolem.kind = self.find(span, &skolem.name)?;
Expand Down Expand Up @@ -297,7 +298,7 @@ impl<'a> KindCheck<'a> {
mut actual: ArcKind,
) -> Result<ArcKind> {
debug!("Unify {:?} <=> {:?}", expected, actual);
let result = unify::unify(&self.subs, (), expected, &actual);
let result = unify::unify(&self.subs, &self.kind_cache, expected, &actual);
match result {
Ok(k) => Ok(k),
Err(_errors) => {
Expand Down Expand Up @@ -423,18 +424,20 @@ impl Substitutable for ArcKind {
}
}

impl<S> Unifiable<S> for ArcKind {
impl<'a> Unifiable<&'a KindCache> for ArcKind {
type Error = KindError<Symbol>;

fn zip_match<U>(
&self,
other: &Self,
unifier: &mut UnifierState<S, U>,
unifier: &mut UnifierState<&'a KindCache, U>,
) -> StdResult<Option<Self>, Error<Symbol>>
where
UnifierState<S, U>: Unifier<S, Self>,
UnifierState<&'a KindCache, U>: Unifier<&'a KindCache, Self>,
{
match (&**self, &**other) {
(_, &Kind::Error) => Ok(None),
(&Kind::Error, _) => Ok(Some(other.clone())),
(&Kind::Function(ref l1, ref l2), &Kind::Function(ref r1, ref r2)) => {
let a = unifier.try_match(l1, r1);
let r = unifier.try_match(l2, r2);
Expand All @@ -447,4 +450,8 @@ impl<S> Unifiable<S> for ArcKind {
},
}
}

fn error_type(state: &&'a KindCache) -> Self {
state.error()
}
}
7 changes: 4 additions & 3 deletions check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub mod unify_type;

mod implicits;

use base::types::{ArcType, TypeEnv};
use base::types::{ArcType, TypeCache, TypeEnv};

/// Checks if `actual` can be assigned to a binding with the type signature `signature`
pub fn check_signature(env: &TypeEnv, signature: &ArcType, actual: &ArcType) -> bool {
Expand All @@ -44,11 +44,12 @@ pub fn check_signature(env: &TypeEnv, signature: &ArcType, actual: &ArcType) ->
use substitution::Substitution;

let subs = Substitution::new(Kind::typ());
let state = unify_type::State::new(env, &subs);
let type_cache = TypeCache::new();
let state = unify_type::State::new(env, &subs, &type_cache);
let actual = unify_type::new_skolem_scope(&subs, actual);
let actual = actual.instantiate_generics(&mut FnvMap::default());
let result = unify_type::subsumes(&subs, &mut ScopedMap::new(), 0, state, signature, &actual);
if let Err(ref err) = result {
if let Err((_, ref err)) = result {
warn!("Check signature error: {}", err);
}
result.is_ok()
Expand Down
12 changes: 12 additions & 0 deletions check/src/substitution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,18 @@ pub trait Substitutable: Sized {
type Factory: VariableFactory<Variable = Self::Variable>;
/// Constructs a new object from its variable type
fn from_variable(x: Self::Variable) -> Self;

/// Retrieves the variable if `self` is a variable otherwise returns `None`
fn get_var(&self) -> Option<&Self::Variable>;

fn get_id(&self) -> Option<u32> {
self.get_var().map(|var| var.get_id())
}

fn traverse<'a, F>(&'a self, f: &mut F)
where
F: Walker<'a, Self>;

fn instantiate(&self, subs: &Substitution<Self>) -> Self;

fn on_union(&self) -> Option<&Self> {
Expand Down Expand Up @@ -339,6 +346,7 @@ impl<T: Substitutable + Clone> Substitution<T> {
*typ = self.real(typ).clone();
}
}

impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
/// Takes `id` and updates the substitution to say that it should have the same type as `typ`
pub fn union(&self, id: &T::Variable, typ: &T) -> Result<Option<T>, Error<T>>
Expand Down Expand Up @@ -379,6 +387,10 @@ impl<T: Substitutable + PartialEq + Clone> Substitution<T> {
self.update_level(other_id, id.get_id());
}
_ => {
if let Some(other_id) = typ.get_id() {
self.update_level(id.get_id(), other_id);
}

self.insert(id.get_id(), typ.clone());
}
}
Expand Down
Loading

0 comments on commit 2562070

Please sign in to comment.