Skip to content

Commit

Permalink
feat(check): Allow non-Type kinded types at the top of aliases
Browse files Browse the repository at this point in the history
More of a fix but this works

```
type Test a = { x : a }
type Test2 = Test
```

Closes #186
  • Loading branch information
Marwes committed Jan 31, 2019
1 parent 4da5b5f commit 126eceb
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 29 deletions.
10 changes: 5 additions & 5 deletions base/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl AliasRemover {
) -> Result<Cow<'t, T>, Error>
where
F: FnMut(&AliasRef<Symbol, T>) -> bool,
T: TypeExt<Id = Symbol> + Clone,
T: TypeExt<Id = Symbol> + Clone + ::std::fmt::Display,
{
Ok(match peek_alias(env, typ) {
Ok(Some(alias)) => {
Expand Down Expand Up @@ -84,7 +84,7 @@ impl AliasRemover {
mut typ: T,
) -> Result<T, Error>
where
T: TypeExt<Id = Symbol>,
T: TypeExt<Id = Symbol> + ::std::fmt::Display,
{
loop {
typ = match self.remove_alias(env, interner, &typ)? {
Expand All @@ -101,7 +101,7 @@ impl AliasRemover {
typ: &T,
) -> Result<Option<T>, Error>
where
T: TypeExt<Id = Symbol>,
T: TypeExt<Id = Symbol> + ::std::fmt::Display,
{
match peek_alias(env, &typ)? {
Some(alias) => {
Expand Down Expand Up @@ -162,7 +162,7 @@ pub fn canonical_alias<'t, F, T>(
) -> Cow<'t, T>
where
F: FnMut(&AliasRef<Symbol, T>) -> bool,
T: TypeExt<Id = Symbol> + Clone,
T: TypeExt<Id = Symbol> + Clone + ::std::fmt::Display,
{
match peek_alias(env, typ) {
Ok(Some(alias)) => {
Expand Down Expand Up @@ -208,7 +208,7 @@ pub fn peek_alias<'t, T>(
typ: &'t T,
) -> Result<Option<&'t AliasRef<Symbol, T>>, Error>
where
T: TypeExt<Id = Symbol>,
T: TypeExt<Id = Symbol> + ::std::fmt::Display,
{
let maybe_alias = typ.applied_alias();

Expand Down
23 changes: 13 additions & 10 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,15 +1116,9 @@ where
}

pub fn applied_alias(&self) -> Option<&AliasRef<Id, T>> {
self.applied_alias_(0)
}

fn applied_alias_(&self, given_arguments_count: usize) -> Option<&AliasRef<Id, T>> {
match *self {
Type::Alias(ref alias) if alias.params().len() == given_arguments_count => Some(alias),
Type::App(ref alias, ref args) => {
alias.applied_alias_(args.len() + given_arguments_count)
}
Type::Alias(ref alias) => Some(alias),
Type::App(ref alias, _) => alias.applied_alias(),
_ => None,
}
}
Expand Down Expand Up @@ -1513,9 +1507,18 @@ pub trait TypeExt: Deref<Target = Type<<Self as TypeExt>::Id, Self>> + Clone + S
.map(|g| g.id.clone())
.zip(args.iter().cloned())
.collect();

let typ = typ
.replace_generics(interner, &mut map)
.unwrap_or_else(|| typ.clone());
Some(
typ.replace_generics(interner, &mut map)
.unwrap_or_else(|| typ.clone()),
interner.app(
typ,
args[params.len().min(args.len())..]
.iter()
.cloned()
.collect(),
),
)
}

Expand Down
54 changes: 47 additions & 7 deletions base/tests/types.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
#[macro_use]
extern crate collect_mac;
extern crate gluon_base as base;
extern crate pretty;
#[macro_use]
extern crate pretty_assertions;

use std::ops::Deref;
use std::{cell::RefCell, ops::Deref, rc::Rc};

use pretty::{Arena, DocAllocator};

use base::ast::{Expr, Literal, SpannedExpr, Typed, TypedIdent};
use base::kind::{ArcKind, Kind, KindEnv};
use base::pos::{self, BytePos, Span, Spanned};
use base::symbol::{Symbol, SymbolRef, Symbols};
use base::types::*;
use base::{
ast::{Expr, Literal, SpannedExpr, Typed, TypedIdent},
kind::{ArcKind, Kind, KindEnv},
pos::{self, BytePos, Span, Spanned},
resolve,
symbol::{Symbol, SymbolRef, Symbols},
types::*,
};

fn type_con<I, T>(s: I, args: Vec<T>) -> Type<I, T>
where
Expand Down Expand Up @@ -353,8 +358,15 @@ impl TypeEnv for MockEnv {

pub type SpExpr = SpannedExpr<Symbol>;

pub fn get_local_interner() -> Rc<RefCell<Symbols>> {
thread_local!(static INTERNER: Rc<RefCell<Symbols>>
= Rc::new(RefCell::new(Symbols::new())));

INTERNER.with(|interner| interner.clone())
}

pub fn intern(s: &str) -> Symbol {
Symbol::from(s)
get_local_interner().borrow_mut().symbol(s)
}

pub fn no_loc<T>(value: T) -> Spanned<T, BytePos> {
Expand Down Expand Up @@ -386,3 +398,31 @@ fn take_implicits_into_account_on_infix_type() {

assert_eq!(expr.env_type_of(&MockEnv), Type::int());
}

#[test]
fn resolve_partially_applied_alias() {
let gen = |x: &str| Type::<_, ArcType>::generic(Generic::new(intern(x), Kind::typ()));
let test = Type::alias(
intern("Test"),
vec![
Generic::new(intern("a"), Kind::typ()),
Generic::new(intern("b"), Kind::typ()),
],
Type::function(vec![gen("a")], gen("b")),
);
let test2 = Type::alias(
intern("Test2"),
vec![],
Type::app(test.clone(), collect![Type::string()]),
);

assert_eq_display!(
resolve::remove_aliases(
&MockEnv,
&mut NullInterner,
Type::app(test2, collect![Type::int()])
)
.to_string(),
"String -> Int"
);
}
4 changes: 2 additions & 2 deletions check/src/kindcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ impl<'a> KindCheck<'a> {

// Kindhecks `typ`, infering it to be of kind `Type`
pub fn kindcheck_type(&mut self, typ: &mut AstType<Symbol>) -> Result<ArcKind> {
let type_kind = self.type_kind();
self.kindcheck_expected(typ, &type_kind)
let any = self.subs.new_var();
self.kindcheck_expected(typ, &any)
}

pub fn kindcheck_expected(
Expand Down
6 changes: 1 addition & 5 deletions check/tests/fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,7 @@ type Bar = Test Int
()
"#;
let result = support::typecheck(text);
assert_err!(
result,
KindError(TypeMismatch(..)),
KindError(TypeMismatch(..))
);
assert_err!(result, KindError(TypeMismatch(..)));
}

#[test]
Expand Down
11 changes: 11 additions & 0 deletions check/tests/pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,3 +1022,14 @@ let (+) x y : a -> a -> a = y
assert!(result.is_ok(), "{}", result.unwrap_err());
assert_eq!(expr.env_type_of(&MockEnv::new()).to_string(), "Int");
}

test_check! {
partially_applied_alias_def,
r#"
type Test a b = (a, b)
type Test2 = Test Int
let x : Test2 String = (1, "")
x
"#,
"test.Test2 String"
}

0 comments on commit 126eceb

Please sign in to comment.