package nl.utwente.viskell.haskell.type; import nl.utwente.viskell.haskell.env.Environment; import nl.utwente.viskell.haskell.env.HaskellCatalog; import org.junit.Test; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; public class ClassesTest { @Test public final void testCompareTo() { TypeScope scope = new TypeScope(); final TypeVar a = scope.getVar("a"); final TypeVar b = scope.getVarTC("b", new TypeClass("Test")); assertEquals(a, a); assertEquals(b, b); final TypeVar a2 = scope.getVar("a"); final TypeVar b2 = scope.getVar("b"); assertEquals(a, a2); assertEquals(b, b2); TypeScope scope2 = new TypeScope(); assertThat(a, is(not(scope2.getVar("a")))); assertThat(b, is(not(scope2.getVar("b")))); TypeScope scope3 = new TypeScope(); assertThat(b, is(not(scope3.getVarTC("b", new TypeClass("Test"))))); } @Test public final void testSuperClasses() throws HaskellTypeError { final Environment env = new HaskellCatalog().asEnvironment(); final TypeClass eq = env.testLookupClass("Eq"); final TypeClass ord = env.testLookupClass("Ord"); final TypeClass integral = env.testLookupClass("Integral"); TypeScope scope = new TypeScope(); final TypeVar a = scope.getVarTC("a", eq); final TypeVar b = scope.getVarTC("b", ord); TypeChecker.unify("test", a, b); // the Eq constraint disappears because it is direct superclass of Ord assertEquals("Ord b", a.prettyPrint()); assertEquals("Ord b", b.prettyPrint()); final TypeVar c = scope.getVarTC("c", integral); final TypeVar d = scope.getVarTC("d", ord); TypeChecker.unify("test", c, d); // indirectly through Real, Ord is also implied by Integral assertEquals("Integral d", c.prettyPrint()); assertEquals("Integral d", d.prettyPrint()); } @Test public final void testNestedTypes() throws HaskellTypeError { final Environment env = new HaskellCatalog().asEnvironment(); final TypeClass eq = env.testLookupClass("Eq"); final TypeClass ord = env.testLookupClass("Ord"); final TypeClass show = env.testLookupClass("Show"); final TypeClass num = env.testLookupClass("Num"); TypeScope scope = new TypeScope(); final TypeVar a = scope.getVar("a"); final TypeVar b = scope.getVar("b"); final Type tab = Type.tupleOf(a, b ,a); final TypeVar x = scope.getVarTC("x", eq); TypeChecker.unify("test", tab, x); assertEquals("Eq a", a.prettyPrint()); assertEquals("Eq b", b.prettyPrint()); assertEquals("(Eq a, Eq b, Eq a)", x.prettyPrint()); final TypeVar c = scope.getVarTC("c", num); final Type mc = Type.con("Maybe", c); final TypeVar y = scope.getVarTC("y", ord); TypeChecker.unify("test", y, mc); assertEquals("(Num+Ord c)", c.prettyPrint()); assertEquals("Maybe (Num+Ord c)", y.prettyPrint()); final Type str = Type.listOf(Type.con("Char")); final TypeVar z = scope.getVarTC("z", show); TypeChecker.unify("test", str, z); assertEquals("[Char]", z.prettyPrint()); } @Test(expected = HaskellTypeError.class) public final void testUnsatisfiable() throws HaskellTypeError { final Environment env = new HaskellCatalog().asEnvironment(); TypeScope scope = new TypeScope(); TypeVar a = scope.getVarTC("a", env.testLookupClass("Integral")); TypeVar b = scope.getVarTC("b", env.testLookupClass("Fractional")); // throw error because, no type exist that is both instance of integral and fractional TypeChecker.unify("test", a, b); } }