/** * 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.junit.Assert.assertEquals; import org.junit.Test; import abs.frontend.FrontendTest; import abs.frontend.analyser.ErrorMessage; import abs.frontend.ast.Model; public class NegativeTypeCheckerTests extends FrontendTest { // NEGATIVE TESTS @Test public void testNull() { assertTypeErrors("{ Unit u = null; } "); } @Test public void varDeclAssign() { assertTypeErrors("{ Unit u = True; } "); } @Test public void duplicateVarDecls() { assertTypeErrors("{ Unit u = Unit; Unit u = Unit; }"); } @Test public void duplicateVarDeclsParams() { assertTypeErrors("class C { Unit m(Unit u) { Unit u = Unit; } }"); } @Test public void varDelcaredLater() { assertTypeErrors("{ Unit u = f; Unit f = Unit; }"); } @Test public void testUnresolvableType() { assertTypeErrors("{ I i; }"); } @Test public void testUnresolvableType2() { assertTypeErrors("class C implements I { }"); } @Test public void testUnresolvableType3() { assertTypeErrors("interface J extends I { }"); } @Test public void missingInterface() { assertTypeErrors("class C implements I { } { I i; i = new local C(); }"); } @Test public void parametericDataTypesOK() { assertTypeOK("interface I {} interface J extends I {} data Foo<A> = Bar(A); { J j; Foo<I> f = Bar(j); }"); } @Test public void parametericDataTypeNoTypeArgs() { assertTypeErrors("data Foo<A> = Bar(A) | Nul; { Foo f = Nul; }"); } @Test public void parametericDataTypeNoTypeArgs2() { assertTypeErrors("class Test { { Pair p = Pair(5,Pair(4,5)); } }"); } @Test public void parametericDataTypeNoTypeArgs3() { assertTypeOK("type Euro = Int; type Cent = Int; type Money = Pair<Euro,Cent>;" + "def Money createMoney(Euro e, Cent c) = Pair(e,c); "); } @Test public void parametericDataTypeNoTypeArgs4() { assertTypeErrors("data Foo<A> = Bar(A) | Nul; type Foo2 = Foo; { Foo2 f = Nul; }"); } @Test public void parametericDataTypeIndirect() { assertTypeErrors("data Foo<A> = Bar(A); type Foo2 = Foo<String>; { Foo2 f = Bar(2); }"); } @Test public void testClassError() { assertTypeErrors("interface I {} interface J{} class C implements J {} { I i; i = new local C(); }"); } @Test public void testClassTypeUseError() { assertTypeErrors("class C {} { C c; c = new local C(); }"); } @Test public void testClassDuplicateFields() { assertTypeErrors("class C { Bool b = True; Int b = 5; } "); } @Test public void testClassDuplicateFields2() { assertTypeErrors("class C(Int b) { Bool b = True; } "); } @Test public void testClassFieldAccessWithoutThis() { assertTypeOK("class C(Int b) { Int c = b; } "); } @Test public void testClassDuplicateMethods() { assertTypeErrors("class C { Unit m() {} Bool m() { return True;} } "); } @Test public void functionDuplicateParams() { assertTypeErrors("def Bool f(Bool b, Int b) = True; "); } @Test public void functionNestedErrors() { assertTypeErrors("def X f(Bool b) = True; "); assertTypeErrors("def Bool f(X b) = True; "); assertTypeErrors("def Bool f(Bool b) = Foo(); "); } @Test public void functionWrongReturnType() { assertTypeErrors("def Bool f() = 5; "); } @Test public void dataTypeDuplicateConstructors() { assertTypeErrors("data Foo = Bar | Bar ;"); } @Test public void dataTypeNestedErrors() { assertTypeErrors("data Foo = Bar(X) ;"); } @Test public void dataTypeDuplicateSelectorNames() { assertTypeErrors("data Foo = Bar(X x) | Baz(X x) ;"); } @Test public void dataTypeSelectorNameLikeFunctionName() { assertTypeErrors("data Foo = Bar(X x); def Bool x() = True; "); } @Test public void interfaceDuplicateMethods() { assertTypeErrors("interface I { Unit m(); Unit m(); }"); } @Test public void methodDuplicateParams() { assertTypeErrors("interface I { Unit m(Bool b, Int b); }"); } @Test public void interfaceWrongExtend() { assertTypeErrors("interface I extends Bool {} "); } @Test public void interfaceCyclicExtend() { assertTypeErrors("interface I extends I {} ", ErrorMessage.CYCLIC_INHERITANCE); assertTypeErrors("interface I extends J {} interface J extends I {}", ErrorMessage.CYCLIC_INHERITANCE); } @Test public void interfaceMethodOverride() { assertTypeErrors("interface I { Unit m(); } interface J extends I { Unit m(); }"); } @Test public void interfaceNestedError() { assertTypeErrors("interface I { X m(); }"); } @Test public void interfaceNestedParamError() { assertTypeErrors("interface I { Unit m(X x); }"); } @Test public void interfaceDupParams() { assertTypeErrors("interface I { Unit m(Bool b, Int b); }"); } @Test public void methodNotImplemented() { assertTypeErrors("interface I { Unit m(); }" + "class C implements I { } "); } @Test public void methodOverrideWrongReturnType() { assertTypeErrors("interface I { Unit m(); }" + "class C implements I { Bool m() { return True; } } "); } @Test public void classMethodWrongNumParams() { assertTypeErrors("interface I { Unit m(); } class C implements I { Unit m(Bool b) { } }"); } @Test public void classMethodWrongParamType() { assertTypeErrors("interface I { Unit m(Bool b); } class C implements I { Unit m(Int i) { } }"); } @Test public void classDuplicateFields() { assertTypeErrors("class C { Bool f; Int f;}"); } @Test public void classFieldError() { assertTypeErrors("class C { X f; }"); } @Test public void classFieldAccess() { assertTypeErrors("class C { Bool f = True; Unit m(Int f) { this.f = 5; } }"); } @Test public void classInitializerBlockError() { assertTypeErrors("class C { { X f; } }"); } @Test public void classParamsError() { assertTypeErrors("class C(I i) { }"); } @Test public void negTestError() { Model m = assertParseOkStdLib(" { Bool b = !5; }"); assertEquals(ErrorMessage.EXPECTED_TYPE, m.typeCheck().getFirstError().msg); } @Test public void plusError() { assertTypeErrors("{ Int i = 4 + True; }"); } @Test public void plusError2() { assertTypeErrors("{ Int i = 4 + \"a\"; }"); } @Test public void getError() { assertTypeErrors("{ Bool f = True; f.get; }"); } @Test public void orError() { assertTypeErrors("{ Bool b = True || 5; }"); } @Test public void andError() { assertTypeErrors("{ Bool b = 5 && True; }"); } @Test public void newError() { assertTypeErrors("interface I { } { I i; i = new local I(); }"); } @Test public void newError2() { assertTypeErrors("interface I { } class C(Bool b) implements I { } { I i; i = new local C(); }"); } @Test public void newError3() { assertTypeErrors("interface I { } class C(Bool b) implements I { } { I i; i = new local C(5); }"); } @Test public void letError() { assertTypeErrors("{ Bool b = let (Bool x) = 5 in x; }"); } @Test public void caseError() { assertTypeErrors("{ Bool x = True; Bool b = case x { True => False; False => 5; }; }"); } @Test public void caseErrorNoDataType() { assertTypeErrors("interface I { } { I i; Bool b = case i { True => False; False => 5; }; }"); } @Test public void caseBoundVarWrongType() { assertTypeErrors("def Bool f(Bool x) = let (Int y) = 5 in case x { y => True; };"); } @Test public void caseErrorConstructorNotResolvable() { assertTypeErrors("{ Bool x = True; Bool b = case x { Foo => False; }; }"); } @Test public void caseErrorDuplicateFunctionTypeParameter() { assertTypeErrors("def A f<A,A>(A a) = a;"); } public void caseErrorDuplicateDatatypeTypeParameter() { assertTypeErrors("data X<A, A>;"); } @Test public void ticket188() { assertTypeErrors( "def Bool f(List<Bool> list) =" +" case list {" +" Insert(xyz,_) => xyz;" // Insert is not a List constructor +" };"); } @Test public void caseErrorConstructorWrongArgNum() { assertTypeErrors("{ Bool x = True; Bool b = case x { True(5) => False; }; }"); } @Test public void caseErrorConstructorWrongArgType() { assertTypeErrors("data Foo = Bar(Bool); { Foo x = Bar(True); Bool b = case x { Bar(5) => False; }; }"); } @Test public void caseErrorConstructorExpWrongArgType() { assertTypeErrors("data Foo = Bar(Bool); { Foo x = Bar(5); }"); } @Test public void fnAppMissingDef() { assertTypeErrors("def Bool f() = x(); "); } @Test public void fnAppWrongArgNum() { assertTypeErrors("def Bool f() = f(True); "); } @Test public void fnAppWrongArgType() { assertTypeErrors("def Bool f(Bool b) = f(5); "); } @Test public void fnTypecheckNoCrash() { assertTypeErrors("def List<String> map2list<A>(Map<String,A> map) =" + "case map {" + "EmptyMap => Nil ;" + "Insert(Pair(b,_), tail) => Cons(b, map2list(tail)) ;" + "};"); } @Test public void missingConstructorNoSO() { /* Frob not visible, gave once an SO */ assertTypeErrors("type Tuple = Map<Int, Int>;" +"def Bool tupleMatches(Tuple tuple, Tuple criterion) =" +"case criterion {" +" Frob(pair, rest) =>" +" lookup(tuple, fst(pair)) == Just(snd(pair)) &&" +" tupleMatches(tuple, rest);" +" EmptyMap => True;" +"};"); } @Test public void methodReturnError() { assertTypeErrors("class C { Unit m() { return True; } }"); } @Test public void methodMissingReturn() { assertTypeErrors("class C { Bool m() { } }", ErrorMessage.CANNOT_ASSIGN); } @Test public void methodReturnNotLastStmt() { assertTypeErrors("class C { Bool m() { if (True) return True; else return False; return True;} }"); } @Test public void syncCallWrongTarget() { assertTypeErrors("class C { Unit m(Bool b) { b.m(); } }"); } @Test public void syncCallNoMethodThis() { assertTypeErrors("class C { Unit m() { this.n(); } }"); } @Test public void syncCallNoMethodIntf() { assertTypeErrors("interface I {} { I i; i.m(); }"); } @Test public void syncCallWrongArgNum() { assertTypeErrors("interface I { Unit m(); } { I i; i.m(True); }"); } @Test public void syncCallWrongArgType() { assertTypeErrors("interface I { Unit m(Int i); } { I i; i.m(True); }"); } @Test public void testVarDeclInitNoSubtypeError() { assertTypeErrors("interface I {} interface J {} { J j; I i = j; }"); } @Test public void testVarDeclInitMissingError() { assertTypeErrors("{ Bool b; }"); } @Test public void testIfNoBool() { assertTypeErrors("{ if (5) { } else { } }"); } @Test public void testWhileNoBool() { assertTypeErrors("{ while (5) { } }"); } @Test public void testAwaitNoFut() { assertTypeErrors("{ Bool b = True; await b?; }"); } @Test public void testGetNoFut() { assertTypeErrors("{ Either<Unit,Bool> e = Right(True); e.get; }", ErrorMessage.EXPECTED_FUT_TYPE); } @Test public void testAwaitNoBool() { assertTypeErrors("{ await 5; }"); } @Test public void testAwaitAndError() { assertTypeErrors("{ await 5 && True; }"); } @Test public void constructorTypeArgsError() { assertTypeErrors("data Foo<A> = Bar(A,A); { Foo<A> o = Bar(True,5); }"); } @Test public void missingTypArg() { assertTypeErrors("def List<A> map2list<A>(Map<A,B> map) = Nil;"); } @Test public void returnInMainBlock() { assertTypeErrors("{ return Nil; }"); assertTypeErrors("{ return Unit; return Unit; }"); } @Test public void returnInInitBlock() { assertTypeErrors("class C { { return Nil; } }"); assertTypeErrors("class C { { return Unit; return Unit; } }"); } @Test public void initCodeBlock() { assertTypeErrors("class C { { await True; } }"); assertTypeErrors("class C { { Fut<Unit> f; f.get; } }"); assertTypeErrors("class C { { this.m(); } Unit m() { }}"); assertTypeOK("class C { { this.m(); } [Atomic] Unit m() { }}"); } @Test public void init_this() { assertTypeErrors("class C {} { this.f(); }"); } @Test public void wrongNumberOfParams() { assertTypeErrors("module Bug;" + "def String f (String name) = name;" + "{ List<String> s = Cons(f(\"foo\", Nil)); }", ErrorMessage.WRONG_NUMBER_OF_ARGS); } @Test public void overloadingOfImplementedInterfacesInClass() { assertTypeErrors("module Test; interface A { Unit m(); } interface B { Unit m(Int x); } class C implements A, B { Unit m() { skip; }}"); } @Test public void overloadingOfImplementedInterfacesInInterface() { assertTypeErrors("module Test; interface A { Unit m(); } interface B { Unit m(Int x); } interface I extends A, B { }"); } @Test public void uninitializedVariable() { assertTypeErrors(" { Int x = x; }"); } @Test public void wrongInitOrder() { assertTypeErrors(" class C { Int x = y + 1; Int y = 1; }"); } @Test public void wrongInitOrder1() { assertTypeErrors(" class C { Int x = this.y + 1; Int y = 1; }"); } @Test public void wrongInitOrder2() { assertTypeErrors(" class C { Int x = x + 1; }"); } @Test public void rightInitOrder() { assertTypeOK(" class C { Int y = 1; Int x = y + 1; }"); } @Test public void localVariableHiding() { assertTypeErrors(" class C { Unit foo() { Int x = 1; if (True) { Int x = 2; }} }"); } @Test public void localVariableHiding2() { assertTypeErrors(" class C { Unit foo(Int x) { if (True) { Int x = 2; } } }"); } @Test public void localVariableHiding3() { assertTypeErrors(" class C {{ Int x = 1; if (True) { Int x = 2; }}}"); } @Test public void localVariableHidingOk() { assertTypeOK(" class C { Unit foo() { if (True) { Int x = 1; } if (True) { Int x = 2; }} }"); } @Test public void localVariableHidingOk2() { assertTypeOK(" class C { Unit foo() { if (True) { Int x = 2; } Int x = 1; } }"); } @Test public void localVariableHidingOk3() { assertTypeOK(" class C { Int x = 1; Unit foo() { if (True) { Int x = 2; } } }"); } @Test public void localVariableHidingOk4() { assertTypeOK(" class C { Int x = 1; { Int x = 2; } }"); } @Test public void typeRecursive1() throws Exception { assertTypeErrors("type Foo = Foo;", ErrorMessage.CIRCULAR_TYPESYN); } @Test public void typeRecursive2() throws Exception { assertTypeErrors("type Foo = Bar; type Bar = Foo;", ErrorMessage.CIRCULAR_TYPESYN); } @Test public void constNull1() throws Exception { assertTypeErrors("{ null!m(); }", ErrorMessage.NULL_NOT_HERE); } @Test public void constNull2() throws Exception { assertTypeErrors("{ null.m(); }", ErrorMessage.NULL_NOT_HERE); } @Test public void constructorPatternBorked1() { assertTypeErrors("interface I {} { List<I> is = Nil; Unit u = case is { Cons(I(x), Nil) => Unit; }; }", ErrorMessage.CONSTRUCTOR_NOT_RESOLVABLE); } }