From 126ecebbf0cdde4ff09ee5e9a6b3ad2ef17627f7 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 31 Jan 2019 23:01:03 +0100 Subject: [PATCH] feat(check): Allow non-Type kinded types at the top of aliases More of a fix but this works ``` type Test a = { x : a } type Test2 = Test ``` Closes #186 --- base/src/resolve.rs | 10 ++++---- base/src/types/mod.rs | 23 ++++++++++-------- base/tests/types.rs | 54 ++++++++++++++++++++++++++++++++++++------ check/src/kindcheck.rs | 4 ++-- check/tests/fail.rs | 6 +---- check/tests/pass.rs | 11 +++++++++ 6 files changed, 79 insertions(+), 29 deletions(-) diff --git a/base/src/resolve.rs b/base/src/resolve.rs index 099cc8c3e4..cc05e6f81b 100644 --- a/base/src/resolve.rs +++ b/base/src/resolve.rs @@ -48,7 +48,7 @@ impl AliasRemover { ) -> Result, Error> where F: FnMut(&AliasRef) -> bool, - T: TypeExt + Clone, + T: TypeExt + Clone + ::std::fmt::Display, { Ok(match peek_alias(env, typ) { Ok(Some(alias)) => { @@ -84,7 +84,7 @@ impl AliasRemover { mut typ: T, ) -> Result where - T: TypeExt, + T: TypeExt + ::std::fmt::Display, { loop { typ = match self.remove_alias(env, interner, &typ)? { @@ -101,7 +101,7 @@ impl AliasRemover { typ: &T, ) -> Result, Error> where - T: TypeExt, + T: TypeExt + ::std::fmt::Display, { match peek_alias(env, &typ)? { Some(alias) => { @@ -162,7 +162,7 @@ pub fn canonical_alias<'t, F, T>( ) -> Cow<'t, T> where F: FnMut(&AliasRef) -> bool, - T: TypeExt + Clone, + T: TypeExt + Clone + ::std::fmt::Display, { match peek_alias(env, typ) { Ok(Some(alias)) => { @@ -208,7 +208,7 @@ pub fn peek_alias<'t, T>( typ: &'t T, ) -> Result>, Error> where - T: TypeExt, + T: TypeExt + ::std::fmt::Display, { let maybe_alias = typ.applied_alias(); diff --git a/base/src/types/mod.rs b/base/src/types/mod.rs index 61e15a9d2d..20d64fb126 100644 --- a/base/src/types/mod.rs +++ b/base/src/types/mod.rs @@ -1116,15 +1116,9 @@ where } pub fn applied_alias(&self) -> Option<&AliasRef> { - self.applied_alias_(0) - } - - fn applied_alias_(&self, given_arguments_count: usize) -> Option<&AliasRef> { 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, } } @@ -1513,9 +1507,18 @@ pub trait TypeExt: Deref::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(), + ), ) } diff --git a/base/tests/types.rs b/base/tests/types.rs index 8e5eaba03e..cd99c29fad 100644 --- a/base/tests/types.rs +++ b/base/tests/types.rs @@ -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(s: I, args: Vec) -> Type where @@ -353,8 +358,15 @@ impl TypeEnv for MockEnv { pub type SpExpr = SpannedExpr; +pub fn get_local_interner() -> Rc> { + thread_local!(static INTERNER: Rc> + = 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(value: T) -> Spanned { @@ -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" + ); +} diff --git a/check/src/kindcheck.rs b/check/src/kindcheck.rs index 7f6c9e2071..349375dece 100644 --- a/check/src/kindcheck.rs +++ b/check/src/kindcheck.rs @@ -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) -> Result { - 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( diff --git a/check/tests/fail.rs b/check/tests/fail.rs index 5ab1633459..0c99f98435 100644 --- a/check/tests/fail.rs +++ b/check/tests/fail.rs @@ -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] diff --git a/check/tests/pass.rs b/check/tests/pass.rs index fe5148c701..92ba0e8e01 100644 --- a/check/tests/pass.rs +++ b/check/tests/pass.rs @@ -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" +}