#[macro_use] extern crate collect_mac; extern crate gluon_base as base; extern crate pretty; #[macro_use] extern crate pretty_assertions; use std::{cell::RefCell, iter::FromIterator, ops::Deref, rc::Rc}; use pretty::{Arena, DocAllocator}; use base::{ ast::{self, 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 I: Deref, T: TypeExt + From>, T::Types: FromIterator + Default + Extend, { assert!(s.len() != 0); match s.parse() { Ok(b) => Type::Builtin(b), Err(()) if s.starts_with(char::is_lowercase) => Type::Generic(Generic::new(s, Kind::typ())), Err(()) => Type::App(Type::ident(KindedIdent::new(s)), args.into_iter().collect()), } } macro_rules! assert_eq_display { ($l:expr, $r:expr) => { assert_eq!($l.to_string(), $r.to_string()); }; } #[test] fn show_function() { let int: ArcType<&str> = Type::int(); let int_int = Type::function(vec![int.clone()], int.clone()); assert_eq_display!(format!("{}", int_int), "Int -> Int"); assert_eq_display!( format!("{}", Type::function(vec![int_int.clone()], int.clone())), "(Int -> Int) -> Int" ); assert_eq_display!( format!("{}", Type::function(vec![int.clone()], int_int.clone())), "Int -> Int -> Int" ); } #[test] fn show_forall() { let arg = |id| Generic::new(id, Kind::typ()); let typ: ArcType<&str> = Type::forall(vec![arg("a"), arg("b")], Type::unit()); assert_eq_display!(format!("{}", typ), "forall a b . ()"); } #[test] fn show_record_empty() { let record: ArcType<&str> = Type::record(vec![], vec![]); assert_eq_display!(format!("{}", record), "()"); } #[test] fn show_record_singleton() { let typ: ArcType<&str> = Type::record(vec![], vec![Field::new("x", Type::int())]); assert_eq_display!(format!("{}", typ), "{ x : Int }"); } #[test] fn show_record_singleton_polymorphic() { let data = |s, a| ArcType::from(type_con(s, a)); let fun = Type::function(vec![data("a", vec![])], Type::string()); let typ = Type::record( vec![Field::new( "Test", Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()), )], vec![], ); assert_eq_display!(format!("{}", typ), "{ Test a = a -> String }"); } #[test] fn show_record_multifield() { let data = |s, a| ArcType::from(type_con(s, a)); let fun = Type::function(vec![data("a", vec![])], Type::string()); let typ = Type::record( vec![Field::new( "Test", Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()), )], vec![Field::new("x", Type::int())], ); assert_eq_display!(format!("{}", typ), "{ Test a = a -> String, x : Int }"); } #[test] fn show_record_multiline() { let data = |s, a| ArcType::from(type_con(s, a)); let fun = Type::function( vec![data("a", vec![]), data("a", vec![]), data("a", vec![])], Type::string(), ); let test = data("Test", vec![data("a", vec![])]); let record = Type::record( vec![Field::new( "Test", Alias::from(AliasData::new( "Test", vec![Generic::new("a", Kind::typ())], fun.clone(), )), )], vec![ Field::new("x", Type::int()), Field::new("test", test.clone()), Field::new( "+", Type::function(vec![Type::int(), Type::int()], Type::int()), ), ], ); assert_eq_display!( format!("{}", record), r#"{ Test a = a -> a -> a -> String, x : Int, test : Test a, (+) : Int -> Int -> Int }"# ); } #[test] fn show_record_long_type() { let data = |s, a| ArcType::from(type_con(s, a)); let fun = Type::function( vec![ data( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", vec![], ), data("a", vec![]), data("a", vec![]), ], Type::string(), ); let record = Type::record( vec![Field::new( "Test", Alias::from(AliasData::new( "Test", vec![Generic::new("a", Kind::typ())], fun.clone(), )), )], vec![], ); assert_eq_display!( format!("{}", record), r#"{ Test a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -> a -> a -> String }"# ); } #[test] fn show_record_filtered() { let data = |s, a| ArcType::from(type_con(s, a)); let test = data("Test", vec![data("a", vec![])]); let record = Type::record( vec![Field::new( "Test", Alias::new("Test", Vec::new(), Type::int()), )], vec![ Field::new("x", Type::int()), Field::new("y", Type::int()), Field::new("test", test.clone()), Field::new( "+", Type::function(vec![Type::int(), Type::int()], Type::int()), ), ], ); assert_eq_display!( format!( "{}", TypeFormatter::new(&record).filter(&|field| (*field == "Test").into()) ), r#"{ ..., Test = Int, ... }"# ); assert_eq_display!( format!( "{}", TypeFormatter::new(&record).filter(&|field| (*field != "x").into()) ), r#"{ ..., Test = Int, y : Int, test : Test a, (+) : Int -> Int -> Int, ... }"# ); assert_eq_display!( format!( "{}", TypeFormatter::new(&record) .filter(&|field| (*field != "x").into()) .width(50) ), r#"{ ..., Test = Int, y : Int, test : Test a, (+) : Int -> Int -> Int, ... }"# ); } #[test] fn show_record_multi_line_nested() { let data = |s, a| ArcType::from(type_con(s, a)); let fun = Type::function(vec![data("a", vec![])], Type::string()); let test = data("Test", vec![data("a", vec![])]); let inner_record = Type::record( vec![Field::new( "Test", Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()), )], vec![ Field::new("x", Type::int()), Field::new("test", test.clone()), Field::new( "+", Type::function(vec![Type::int(), Type::int()], Type::int()), ), ], ); let record = Type::record( vec![Field::new( "Test", Alias::new("Test", vec![Generic::new("a", Kind::typ())], fun.clone()), )], vec![ Field::new("x", Type::int()), Field::new( "test", Type::function( vec![ data("Test", vec![Type::int(), fun.clone()]), Type::float(), fun.clone(), fun.clone(), ], fun.clone(), ), ), Field::new( "record_looooooooooooooooooooooooooooooooooong", inner_record, ), Field::new("looooooooooooooooooooooooooooooooooong_field", test.clone()), ], ); let expected = r#"{ Test a = a -> String, x : Int, test : Test Int (a -> String) -> Float -> (a -> String) -> (a -> String) -> a -> String, record_looooooooooooooooooooooooooooooooooong : { Test a = a -> String, x : Int, test : Test a, (+) : Int -> Int -> Int }, looooooooooooooooooooooooooooooooooong_field : Test a }"#; assert_eq_display!(format!("{}", record), expected); } #[test] fn show_variant() { let typ: ArcType<&str> = Type::variant(vec![ Field::new("A", Type::function(vec![Type::int()], Type::opaque())), Field::new("B", Type::opaque()), ]); assert_eq_display!(format!("{}", typ), "| A Int\n| B"); } #[test] fn show_kind() { let two_args = Kind::function(Kind::typ(), Kind::function(Kind::typ(), Kind::typ())); assert_eq_display!(format!("{}", two_args), "Type -> Type -> Type"); let function_arg = Kind::function(Kind::function(Kind::typ(), Kind::typ()), Kind::typ()); assert_eq_display!(format!("{}", function_arg), "(Type -> Type) -> Type"); } #[test] fn show_polymorphic_record() { let fields = vec![Field::new("x", Type::string())]; let typ: ArcType<&str> = Type::poly_record(vec![], fields, Type::ident(KindedIdent::new("r"))); assert_eq_display!(format!("{}", typ), "{ x : String | r }"); } #[test] fn show_polymorphic_record_associated_type() { let type_fields = vec![Field::new( "Test", Alias::new( "Test", vec![Generic::new("a", Kind::typ())], Type::ident(KindedIdent::new("a")), ), )]; let typ: ArcType<&str> = Type::poly_record(type_fields, vec![], Type::ident(KindedIdent::new("r"))); assert_eq_display!(format!("{}", typ), "{ Test a = a | r }"); } #[test] fn break_record() { let data = |s, a| ArcType::from(type_con(s, a)); let test = data("Test", vec![data("a", vec![])]); let typ: ArcType<&str> = Type::record( vec![], vec![ Field::new("x", Type::int()), Field::new("test", test.clone()), Field::new( "+", Type::function(vec![Type::int(), Type::int()], Type::int()), ), ], ); let arena = Arena::<()>::new(); let source = &(); let printer = pretty_print::Printer::new(&arena, source); let typ = arena .text("aaaaaaaaabbbbbbbbbbcccccccccc ") .append(pretty_print(&printer, &typ)) .append(arena.hardline()); assert_eq_display!( format!("{}", typ.1.pretty(80)), r#"aaaaaaaaabbbbbbbbbbcccccccccc { x : Int, test : Test a, (+) : Int -> Int -> Int } "# ); } #[test] fn tuple() { let typ: ArcType = Type::tuple(&mut Symbols::new(), vec![Type::int(), Type::string()]); assert_eq_display!(format!("{}", typ), "(Int, String)"); } pub struct MockEnv; impl KindEnv for MockEnv { fn find_kind(&self, _id: &SymbolRef) -> Option { None } } impl TypeEnv for MockEnv { type Type = ArcType; fn find_type(&self, _id: &SymbolRef) -> Option { None } fn find_type_info(&self, _id: &SymbolRef) -> Option> { None } } pub type SpExpr<'ast> = SpannedExpr<'ast, Symbol>; 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 { get_local_interner().borrow_mut().simple_symbol(s) } pub fn no_loc(value: T) -> Spanned { pos::spanned(Span::default(), value) } pub fn int<'ast>(i: i64) -> SpExpr<'ast> { no_loc(Expr::Literal(Literal::Int(i))) } pub fn binop<'ast>( arena: ast::ArenaRef<'_, 'ast, Symbol>, l: SpExpr<'ast>, s: &str, r: SpExpr<'ast>, ) -> SpExpr<'ast> { no_loc(Expr::Infix { lhs: arena.alloc(l), op: no_loc(TypedIdent::new(intern(s))), rhs: arena.alloc(r), implicit_args: &mut [], }) } #[test] fn take_implicits_into_account_on_infix_type() { base::mk_ast_arena!(arena); let mut expr = binop(arena.borrow(), int(1), "+", int(2)); if let Expr::Infix { ref mut op, .. } = expr.value { op.value.typ = Type::function_implicit( vec![Type::int()], Type::function(vec![Type::int(), Type::int()], Type::int()), ); } 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" ); } #[test] fn forall_hides_generic_flag() { let a = Generic::new("a", Kind::typ()); let gen = Type::<_, ArcType<_>>::generic(a.clone()); assert_eq!(gen.flags(), Flags::HAS_GENERICS); assert_eq!(Type::forall(vec![a], gen).flags(), Flags::HAS_FORALL); }