/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.frontend.typesystem;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
import abs.ABSTest;
import abs.frontend.FrontendTest;
import abs.frontend.analyser.ErrorMessage;
import abs.frontend.analyser.SemanticConditionList;
import abs.frontend.ast.*;
import abs.frontend.typechecker.*;
import abs.frontend.typechecker.KindedName.Kind;
public class TypeCheckerTest extends FrontendTest {
// POSITIVE TESTS
@Test
public void abslang() throws Exception {
assertTypeCheckFileOk("src/abs/lang/abslang.abs", false);
}
@Test
public void lizeth() throws Exception {
assertTypeCheckFileOk("tests/abssamples/lizeth.abs", false);
}
@Test
public void rosetreeTicket187() throws Exception {
assertTypeCheckFileOk("tests/abssamples/RoseTree.abs", true);
}
@Test
public void subtypingTicket101() throws Exception {
// https://github.com/abstools/abstools/issues/101
assertTypeOK("interface I {} class A implements I {} { I a = new A(); List<I> as = list[null, a]; }");
}
@Test
public void tch_npe() throws Exception {
assertTypeErrors("module Test; import ABS.StdLib.Bar; { ABS.StdLib.Bar x; }", Config.EXPECT_TYPE_ERROR);
}
@Test
public void testVarDecl() {
assertNoTypeErrorsNoLib("data Bool = True | False; { Bool b = True; }");
}
@Test
public void testVarDeclInit() {
assertNoTypeErrorsNoLib("interface I {} interface J extends I {} { J j; I i = j; }");
}
@Test
public void fieldInit() {
assertNoTypeErrorsNoLib("interface I {} class C implements I { I i = this; }");
}
@Test
public void testClass() {
assertNoTypeErrorsNoLib("interface I {} class C implements I {} { I i; i = new local C(); }");
}
@Test
public void testClass2() {
assertNoTypeErrorsNoLib("interface I {} interface J {} class C implements I,J {} { J j; j = new local C(); }");
}
@Test
public void dataTypeTest() {
assertNoTypeErrorsNoLib("data Foo = Bar; { Foo f = Bar; }");
}
@Test
public void dataTypeParamTest() {
assertNoTypeErrorsNoLib("data Nop = Nop; data Foo<X> = Bar(X); { Foo<Nop> f = Bar(Nop); }");
}
@Test
public void test_dataTypeParam2base() {
assertNoTypeErrorsNoLib("data AorB<A,B> = A(A) | B(B);");
}
@Test
public void test_dataTypeParam2() {
assertNoTypeErrorsNoLib("data AorB<A,B> = A(A getA) | B(B getB);");
}
@Test
public void dataTypeSelectors() {
assertNoTypeErrorsNoLib("data Foo = Bar(Foo foo) | Baz; { Foo b = foo(Bar(Baz)); }");
}
@Test
public void dataTypeSelectors2() {
assertTypeOK("data User = User(String login, String passwordHash);");
}
@Test
public void dataTypeSelectorsParamType() {
assertTypeOK("data User = User(List<String> names);");
}
@Test
public void dataTypeSelectorsTypeParam() {
assertTypeOK("data User<A> = User(List<A> names); { User<String> s = User(list[\"sdasd\"]); List<String> names = names(s); } ");
}
@Test
public void dataTypeSelectorsTypeParam2() {
assertTypeOK("data Foo<A> = Foo(A f);");
}
@Test
public void negTestOk() {
assertTypeOK("{ Bool b = !True; }");
}
@Test
public void andOk() {
assertTypeOK("{ Bool b = True && False; }");
}
@Test
public void plusOk() {
assertTypeOK("{ Int i = 4 + 5; }");
}
@Test
public void getOk() {
assertTypeOK("{ Fut<Bool> f; Bool b = True; b = f.get; }");
}
@Test
public void ticket414_futNeedsDataType1() {
Model m = assertParseOk("module M; interface I {} { Fut<I> fi; }", Config.WITH_STD_LIB);
assertFalse(m.hasErrors());
Block b = m.getMainBlock();
assertNotNull(b);
VarDeclStmt s = (VarDeclStmt) b.getStmt(0);
ParametricDataTypeUse u = (ParametricDataTypeUse) s.getVarDecl().getAccess();
// Have:
TypeUse tu = u.getParam(0);
assertEquals("I",tu.getName());
assertThat(tu, instanceOf(InterfaceTypeUse.class));
assertThat(tu.getType(), instanceOf(InterfaceType.class));
assertThat(tu.getDecl(), instanceOf(InterfaceDecl.class));
}
@Test
public void ticket414_futNeedsDataType2() {
Model m = assertParseOk("module M; data I = I; { Fut<I> fi; }", Config.WITH_STD_LIB);
assertFalse(m.hasErrors());
Block b = m.getMainBlock();
assertNotNull(b);
VarDeclStmt s = (VarDeclStmt) b.getStmt(0);
ParametricDataTypeUse u = (ParametricDataTypeUse) s.getVarDecl().getAccess();
// Have:
TypeUse tu = u.getParam(0);
assertEquals("I",tu.getName());
assertThat(tu, instanceOf(DataTypeUse.class));
}
@Test
public void letOk() {
assertTypeOK("{ Bool b = let (Bool x) = True in x; }");
}
@Test
public void caseOk() {
assertTypeOK("{ Bool x = True; Bool b = case x { True => False; False => True; }; }");
}
@Test
public void testIfExp1() {
assertTypeOK("def X frob<X>(X x) = x;");
}
@Test
public void testIfExp2() {
assertTypeOK("def X frob<X>(X x) = if (True) then x else x;");
}
@Test
public void caseVarOk() {
assertTypeOK("data Foo = Bar(Bool); { Foo x = Bar(True);" + " Bool b = case x { Bar(y) => y; }; }");
}
@Test
public void methodEmptyOk() {
assertTypeOK("interface I { Unit m(); } class C implements I { Unit m() { } }");
}
@Test
public void methodNoReturnOk() {
assertTypeOK("interface I { Unit m(); } class C implements I { Unit m() { Bool b = True; b = False; } }");
}
@Test
public void methodReturnOk() {
assertTypeOK("interface I { Unit m(); } class C implements I { Unit m() { Bool b = True; return Unit; } }");
}
@Test
public void methodParameterOk() {
assertTypeOK("interface I { Bool m(Bool b);} " + "class C implements I { Bool m(Bool b) { return b; } }");
}
@Test
public void methodInSuperType() {
assertTypeOK("interface I { Bool m(Bool b);} interface J extends I { }"
+ "class C implements J { Bool m(Bool b) { J j; j = this; return j.m(True); } }");
}
@Test
public void testIfOk() {
assertTypeOK("{ if (True) { } else { } }");
}
@Test
public void testWhileOk() {
assertTypeOK("{ while (True) { } }");
}
@Test
public void testAwaitClaimOk() {
assertTypeOK("{ Fut<Bool> f; await f?; }");
}
@Test
public void testAwaitBoolOk() {
assertWarnings("{ Bool b = False; await b; }");
}
@Test
public void testAwaitAndOk() {
assertWarnings("{ await False && True; }");
}
@Test
public void testAwaitTooPure1OK() {
assertTypeOK("{ await timeValue(now()) > 0; }");
}
@Test
public void testAwaitTooPure2OK() {
// recursive def!
assertTypeOK("{ await lookupDefault(insert(EmptyMap, Pair(1,timeValue(now()))),1,0) > 0; }");
}
@Test
public void testAwaitTooPure3() {
// recursive def!
assertWarnings("{ await lookupDefault(insert(EmptyMap, Pair(1,timeValue(Time(0)))),1,0) > 0; }");
}
@Test
public void syncCallMethodThis() {
assertTypeOK("interface I { Unit m(); } " + "class C implements I { Unit m() { this.m(); } }");
}
@Test
public void syncCallMethodThis2() {
assertTypeOK("interface I { Unit m(); } interface J {}"
+ "class C implements J,I { Unit m() { this.m(); } }");
}
@Test
public void syncCallMethodThis3() {
assertTypeOK("interface I { Bool m(); } "
+ "class C implements I { Bool m() { Bool b = True; b = this.m(); return b; } }");
}
@Test
public void syncCallMethodIntf() {
assertTypeOK("interface I { Unit m(); } {I i; i.m(); }");
}
@Test
public void syncCallThis() {
assertTypeOK("class C { Unit m() { this.m(); } }");
}
@Test
public void asyncCallMethodIntf() {
assertTypeOK("interface I { Unit m(); } {I i; i!m(); }");
}
@Test
public void fnAppTypeArgs() {
assertTypeOK("def A f<A>(A a) = a; { Bool b = True; b = f(b); }");
}
@Test
public void fnAppTypeArgs2() {
assertTypeOK("def B optValue<B>(Maybe<B> val) = fromJust(val);");
}
@Test
public void fnAppTypeArgs3() {
assertTypeOK("def List<B> tail2<B>(List<B> list) = tail(list) ; ");
}
@Test
public void fnAppTypeArgs4() {
assertTypeOK("def B nth2<B>(List<B> list, Int n) = nth2(tail(list), n-1) ; ");
}
@Test
public void fnAppTypeArgs5() {
assertTypeOK("def List<B> shuffle<B>(List<B> list) = list;"
+ "def C chose<C>(List<C> list) = head(shuffle(list));");
}
@Test
public void constructorTypeArgs() {
assertTypeOK("{ Maybe<Bool> o = Just(True); }");
}
@Test
public void constructorTypeArgs2() {
assertTypeOK("data Foo<A> = Bar(A,A); { Foo<Bool> o = Bar(True,True); }");
}
@Test
public void constructorTypeArgs3() {
assertTypeOK("data Foo<A,B> = Bar(A,B); { Foo<Bool,Int> o = Bar(True,5); }");
}
@Test
public void constructorTypeArgs4() {
assertTypeOK("{ Either<Int,Bool> o = Left(5); }");
}
@Test
public void synonym1() {
assertTypeOK("type A = Int; type B = A; { B b = 1; }");
}
@Test
public void covariantTypeArgs() {
assertTypeOK("interface I {} " +
"interface J extends I {} " +
"class C implements J {} " +
"{ I i = new local C(); " +
" Maybe<I> o = Just(i); }");
}
@Test
public void testListArgs() {
assertTypeOK(" interface Database { } class DataBaseImpl(Map<String, List<String>> db) implements Database { } "
+ "{ Database db; db = new local DataBaseImpl(map[Pair(\"file0\", list[\"file\", \"from\", \"db\"])]); }");
}
@Test
public void testMaybeDataType() {
assertTypeOK("data MaybeTest<A> = NothingTest | JustTest(A);"
+ "def B fromJustTest<B>(MaybeTest<B> a) = case a { JustTest(j) => j; }; "
+ "{ Bool testresult = fromJustTest(JustTest(True)); }");
}
@Test
public void patternMatching() {
assertNoTypeErrorsNoLib("data List<A> = Nil | Cons(A, List<A>); "
+ "data Pair<A,B> = Pair(A,B); data Server = SomeServer; def Server findServer(Server name, List<Pair<Server, Server>> list) ="
+ "case list { " + "Nil => SomeServer;" + "Cons(Pair(server, set), rest) => server; };");
}
@Test
public void classParams() {
assertTypeOK("interface I { Bool m(); } class C(Bool b) implements I { Bool m() { return b; } }");
}
@Test
public void classParamsMethodShadowsField() {
Model m = assertParseOkStdLib("class C(Bool b) { Bool m(Bool b) { return b; } }");
ModuleDecl u = m.lookupModule("UnitTest");
ClassDecl c = (ClassDecl) u.lookup(new KindedName(Kind.CLASS, "C"));
MethodImpl me = c.lookupMethod("m");
ReturnStmt r = (ReturnStmt) me.getBlock().getStmt(0);
VarOrFieldUse vu = (VarOrFieldUse) r.getRetExp();
ParamDecl d = (ParamDecl) vu.getDecl();
assertThat(d.getParent().getParent(), instanceOf(MethodSig.class));
assertThat(vu.getClass().getName(), vu, instanceOf(VarUse.class));
}
@Test
public void classParamsRewrite() {
Model m = assertParseOkStdLib("class C(Bool b) { Bool m() { return b; } }");
ModuleDecl u = m.lookupModule("UnitTest");
ClassDecl c = (ClassDecl) u.lookup(new KindedName(Kind.CLASS, "C"));
MethodImpl me = c.lookupMethod("m");
ReturnStmt r = (ReturnStmt) me.getBlock().getStmt(0);
VarOrFieldUse vu = (VarOrFieldUse) r.getRetExp();
ParamDecl d = (ParamDecl) vu.getDecl();
assertThat(d.getParent().getParent(), instanceOf(ClassDecl.class));
assertThat(vu.getClass().getName(), vu, instanceOf(FieldUse.class));
}
@Test
public void classParamsRewrite2() {
Model m = assertParseOkStdLib("class C(Bool b) { Bool m(Bool x) { return x; } }");
ModuleDecl u = m.lookupModule("UnitTest");
ClassDecl c = (ClassDecl) u.lookup(new KindedName(Kind.CLASS, "C"));
MethodImpl me = c.lookupMethod("m");
ReturnStmt r = (ReturnStmt) me.getBlock().getStmt(0);
VarOrFieldUse vu = (VarOrFieldUse) r.getRetExp();
ParamDecl d = (ParamDecl) vu.getDecl();
assertThat(d.getParent().getParent(), instanceOf(MethodSig.class));
assertThat(vu.getClass().getName(), vu, instanceOf(VarUse.class));
}
@Test
public void newExp() {
assertTypeOK("class C(Bool b) { } { new local C(True); }");
}
@Test
public void methodSigs() {
Model m = assertParseOk("interface I { Unit m(); } interface J { Unit n(); } interface K extends I, J { Unit foo(); } { K k; } ", Config.WITH_STD_LIB);
ModuleDecl module = m.lookupModule("UnitTest");
InterfaceDecl d = (InterfaceDecl) module.getDecl(2);
ArrayList<MethodSig> list = new ArrayList<MethodSig>(d.getAllMethodSigs());
assertEquals(list.toString(),3,list.size());
VarDeclStmt stmt = (VarDeclStmt) module.getBlock().getStmt(0);
Collection<MethodSig> sigs = stmt.getVarDecl().getAccess().getType().getAllMethodSigs();
assertArrayEquals(sigs.toArray(),d.getAllMethodSigs().toArray());
}
@Test
public void ticket256() {
assertTypeOK("data D = Ticket256(Set<Int>);"
+ "def Set<Int> ticket256(D d) ="
+ " case d {"
+ " Ticket256(ds) => ds;"
+ " };");
}
@Test
public void ticket296() {
assertTypeErrors("module FunArgsTypeCheckBug; def Int f(Map<Int,Int> m) = lookupDefault(m, 42);");
}
@Test
public void test_Movecogto1() {
Model m = assertParseOk("class C { Unit do() { movecogto 1; }}", Config.WITH_STD_LIB);
SemanticConditionList errs = m.typeCheck();
assertTrue(m.hasTypeErrors());
assertEquals(ErrorMessage.EXPECTED_DC, errs.getFirstError().msg);
}
@Test
public void deltaParseBS() throws Exception {
String fileName = "tests/abssamples/PVTest.abs";
Model m = ABSTest.assertParseFileOk(fileName, Config.WITH_STD_LIB);
if (m.hasParserErrors())
fail(m.getParserErrors().get(0).toString());
}
}