diff --git a/aeneas/test/TypeSystemTest.v3 b/aeneas/test/TypeSystemTest.v3 index f29b078d2..b8b641ff6 100644 --- a/aeneas/test/TypeSystemTest.v3 +++ b/aeneas/test/TypeSystemTest.v3 @@ -1,6 +1,18 @@ -def TEST = UnitTest.new("TypeSystem", test); - -def error = System.error("TestError", _); +def T = UnitTests.registerT("typesys:", _, TypeSystemTester.new, _); +def X_ = void( + T("Implicit", testImplicit), + T("Subtype", testSubtype), + T("Upper", testUpper), + T("Widen", testWiden), + T("CommonSuperClass", testCommonSuperClass), + T("Unify", testUnify), + T("UnifyWiden", testUnifyWiden), + T("NewTypeQuery", testNewTypeQuery), + T("NewTypeCast", testNewTypeCast), + T("MaybeEqual", testMaybeEqual), + T("Floats", testFloats), + () +); // Some example types def typeCache = TypeCache.new(); @@ -75,11 +87,11 @@ def cl1(name: string, typeParam: TypeParamType, s: ClassType) -> ClassType { decl.typeEnv = typeEnv; var typecon = V3Class_TypeCon.new(decl, typeCache); var result = ClassType.!(typecon.create1(typeParam)); - TEST.eq(s, result.getSuperType()); + if (s != result.getSuperType()) var x = 1/0; return result; } def sub1(t: Type, typeArg: Type) -> Type { - TEST.eq(1, t.typeCon.arity); + if (1 != t.typeCon.arity) var x = 1/0; return t.typeCon.create1(typeArg); } def tv(name: string, tp: TypeParamType) -> TypeVarType { @@ -124,40 +136,118 @@ def initVariantE() -> ClassType { return variantE; } -// The main testing routine -def test() { - testImplicit(); - testSubtype(); - testUpper(); - testWiden(); - testCommonSuperClass(); - testUnify(); - testUnifyWiden(); - testNewTypeQuery(); - testNewTypeCast(); - testMaybeEqual(); - testFloats(); -} - -def assertRelation(f: (Type, Type) -> bool, op: string, x: bool, a: Type, b: Type) { - if (f(a, b) != x) { - var format = if(x, - "type \"%q\" should be %s to \"%q\"", - "type \"%q\" should not be %s to \"%q\""); - error(Strings.format3(format, a.render, op, b.render)); +private class TypeSystemTester(t: Tester) { + def assertRelation(f: (Type, Type) -> bool, op: string, x: bool, a: Type, b: Type) { + if (f(a, b) != x) { + var format = if(x, + "type \"%q\" should be %s to \"%q\"", + "type \"%q\" should not be %s to \"%q\""); + t.fail3(format, a.render, op, b.render); + } } + def assertImplicit(x: bool, a: Type, b: Type) { + return assertRelation(TypeSystem.isPromotable, "promotable", x, a, b); + } + def assertMaybeEqual(x: bool, a: Type, b: Type) { + return assertRelation(TypeSystem.maybeEqual, "maybe equal", x, a, b); + } + def assertSubtype(x: bool, a: Type, b: Type) { + return assertRelation(TypeSystem.isSubtype, "subtype", x, a, b); + } + def assertImplicitTuple(x: bool, a: Type, b: Type) { + assertImplicit(x, a, b); + assertImplicit(x, t2(a, VOID), t2(b, VOID)); + assertImplicit(x, t2(VOID, a), t2(VOID, b)); + assertImplicit(x, t2(a, a), t2(b, b)); + assertImplicit(x, t2(a, I32), t2(b, I64)); + } + def assertUpper(x: Type, a: Type, b: Type) { + var r1 = TypeSystem.upper(a, b); + if (r1 != x) { + var buf = StringBuilder.new(); + buf.puts("expected upper(") + .put1("%q", renderer(a)) + .puts(", ") + .put1("%q", renderer(b)) + .puts(") = ") + .put1("%q", renderer(x)) + .puts(", got ") + .put1("%q", renderer(r1)); + t.fail(buf.toString()); + } + var r2 = TypeSystem.upper(b, a); + if (r1 != r2) { + var buf = StringBuilder.new(); + buf.put2("upper(%q, %q) != ", renderer(a), renderer(b)) + .put2("upper(%q, %q), got ", renderer(b), renderer(a)) + .put2("%q and %q", renderer(r1), renderer(r2)); + t.fail(buf.toString()); + } + } + def assertUpperTuple(x: Type, a: Type, b: Type) { + assertUpper(t2n(a, a), t2(a, a), t2(a, a)); + assertUpper(t2n(x, x), t2(a, a), t2(b, b)); + assertUpper(t2n(a, x), t2(a, a), t2(a, b)); + assertUpper(t2n(x, a), t2(a, a), t2(b, a)); + assertUpper(t2n(x, VOID), t2(a, VOID), t2(b, VOID)); + assertUpper(t2n(VOID, x), t2(VOID, a), t2(VOID, b)); + } + def assertUpperFunction(x: Type, l: Type, a: Type, b: Type) { + assertUpper(x, a, b); + assertUpper(f1n(a, a), f1(a, a), f1(a, a)); + assertUpper(f1n(b, b), f1(b, b), f1(b, b)); + if (x == null) { + assertUpper(null, f1(a, a), f1(b, b)); + assertUpper(null, f1(a, a), f1(a, b)); + assertUpper(x, f1(a, a), f1(b, a)); + } else { + assertUpper(fn(l, VOID), f1(a, VOID), f1(b, VOID)); + assertUpper(f1(VOID, x), f1(VOID, a), f1(VOID, b)); + } + } + def assertTypeQuery(castOp: TypeQuery, a: Type, b: Type) { + var t = TypeSystem.newTypeQuery(a, b); + if (t != castOp) { + var buf = StringBuilder.new(); + buf.put2("expected newTypeQuery(%q, %q) = ", a.render, b.render) + .put2("%s, got %s", castOp.name, t.name); + this.t.fail(buf.toString()); + } + } + def assertTypeCast(castOp: TypeCast, a: Type, b: Type) { + var t = TypeSystem.newTypeCast(a, b); + if (t != castOp) { + var buf = StringBuilder.new(); + buf.put2("expected newTypeCast(%q, %q) = ", a.render, b.render) + .put2("%s, got %s", castOp.name, t.name); + this.t.fail(buf.toString()); + } + } + def assertWiden(expected: Type, a: Type, b: Type) { + var got = TypeSystem.widen(a, b); + if (expected != got) { + var buf = StringBuilder.new(); + buf.put2("expected TypeSystem.widen(%q, %q) == ", a.render, b.render); + if (expected == null) buf.puts(""); + else expected.render(buf); + buf.puts(", got "); + if (got == null) buf.puts(""); + else got.render(buf); + t.fail(buf.toString()); + } + var g2 = TypeSystem.widen(b, a); + if (g2 != got) { + var buf = StringBuilder.new(); + buf.put2("TypeSystem.widen(%q, %q) is not commutative", a.render, b.render); + t.fail(buf.toString()); + } + } + // yyy } -def assertImplicit = assertRelation(TypeSystem.isPromotable, "promotable", _, _, _); -def assertImplicitTuple(x: bool, a: Type, b: Type) { - assertImplicit(x, a, b); - assertImplicit(x, t2(a, VOID), t2(b, VOID)); - assertImplicit(x, t2(VOID, a), t2(VOID, b)); - assertImplicit(x, t2(a, a), t2(b, b)); - assertImplicit(x, t2(a, I32), t2(b, I64)); -} -def testImplicit() { - def Y = assertImplicit(true, _, _); - def N = assertImplicit(false, _, _); + +def testImplicit(t: TypeSystemTester) { + def Y = t.assertImplicit(true, _, _); + def N = t.assertImplicit(false, _, _); for (t in some) Y(t, t); @@ -188,9 +278,10 @@ def testImplicit() { N(s2, s1); } // test implicit conversion between tuple types - assertImplicitTuple(true, I32, I64); - assertImplicitTuple(false, I64, I32); - for (t in some) assertImplicitTuple(true, t, t); + t.assertImplicitTuple(true, I32, I64); + t.assertImplicitTuple(false, I64, I32); + var tt = t; + for (t in some) tt.assertImplicitTuple(true, t, t); // test implicit conversion between function types def fA = f1(VOID, CLASS_A); @@ -204,7 +295,7 @@ def testImplicit() { // Test type parameters and type variables var types = [PARAM_P, PARAM_Q, VAR_V, VAR_W]; for (t in types) for (u in types) { - assertImplicit(t == u, t, u); + tt.assertImplicit(t == u, t, u); } // parameterized class types Y(CLASS_Z_P, CLASS_Y_P); @@ -221,10 +312,9 @@ def testImplicit() { N(CLASS_Y_P, CLASS_Y_Q); } -def assertSubtype = assertRelation(TypeSystem.isSubtype, "subtype", _, _, _); -def testSubtype() { - def Y = assertSubtype(true, _, _); - def N = assertSubtype(false, _, _); +def testSubtype(t: TypeSystemTester) { + def Y = t.assertSubtype(true, _, _); + def N = t.assertSubtype(false, _, _); Y(NULL, STRING); Y(NULL, CLASS_A); @@ -256,7 +346,7 @@ def testSubtype() { var numerics = [FLOAT, DOUBLE, I32, I64]; for (x in numerics) { for (y in numerics) { - assertSubtype(x == y, x, y); + t.assertSubtype(x == y, x, y); } } @@ -282,8 +372,9 @@ def testSubtype() { // Test type parameters and type variables var types = [PARAM_P, PARAM_Q, VAR_V, VAR_W]; + var tt = t; for (t in types) for (u in types) { - assertSubtype(t == u, t, u); + tt.assertSubtype(t == u, t, u); } // parameterized class types Y(CLASS_Z_P, CLASS_Y_P); @@ -300,67 +391,22 @@ def testSubtype() { N(CLASS_Y_P, CLASS_Y_Q); } -def assertUpper(x: Type, a: Type, b: Type) { - var r1 = TypeSystem.upper(a, b); - if (r1 != x) { - var buf = StringBuilder.new(); - buf.puts("expected upper(") - .put1("%q", renderer(a)) - .puts(", ") - .put1("%q", renderer(b)) - .puts(") = ") - .put1("%q", renderer(x)) - .puts(", got ") - .put1("%q", renderer(r1)); - error(buf.toString()); - } - var r2 = TypeSystem.upper(b, a); - if (r1 != r2) { - var buf = StringBuilder.new(); - buf.put2("upper(%q, %q) != ", renderer(a), renderer(b)) - .put2("upper(%q, %q), got ", renderer(b), renderer(a)) - .put2("%q and %q", renderer(r1), renderer(r2)); - error(buf.toString()); - } - -} -def assertUpperTuple(x: Type, a: Type, b: Type) { - assertUpper(t2n(a, a), t2(a, a), t2(a, a)); - assertUpper(t2n(x, x), t2(a, a), t2(b, b)); - assertUpper(t2n(a, x), t2(a, a), t2(a, b)); - assertUpper(t2n(x, a), t2(a, a), t2(b, a)); - assertUpper(t2n(x, VOID), t2(a, VOID), t2(b, VOID)); - assertUpper(t2n(VOID, x), t2(VOID, a), t2(VOID, b)); -} -def assertUpperFunction(x: Type, l: Type, a: Type, b: Type) { - assertUpper(x, a, b); - assertUpper(f1n(a, a), f1(a, a), f1(a, a)); - assertUpper(f1n(b, b), f1(b, b), f1(b, b)); - if (x == null) { - assertUpper(null, f1(a, a), f1(b, b)); - assertUpper(null, f1(a, a), f1(a, b)); - assertUpper(x, f1(a, a), f1(b, a)); - } else { - assertUpper(fn(l, VOID), f1(a, VOID), f1(b, VOID)); - assertUpper(f1(VOID, x), f1(VOID, a), f1(VOID, b)); - } -} -def testUpper() { - def N = assertUpper(null, _, _); - for (x in some) assertUpper(x, x, x); +def testUpper(t: TypeSystemTester) { + def N = t.assertUpper(null, _, _); + for (x in some) t.assertUpper(x, x, x); N(I32, I64); N(CLASS_X, CLASS_A); - assertUpper(VOID, VOID, VOID); - assertUpper(CLASS_A, CLASS_A, CLASS_B); - assertUpper(CLASS_A, CLASS_A, CLASS_C); - assertUpper(CLASS_A, CLASS_B, CLASS_C); + t.assertUpper(VOID, VOID, VOID); + t.assertUpper(CLASS_A, CLASS_A, CLASS_B); + t.assertUpper(CLASS_A, CLASS_A, CLASS_C); + t.assertUpper(CLASS_A, CLASS_B, CLASS_C); - assertUpper(VARIANT_E, VARIANT_E, CASE_G); - assertUpper(VARIANT_E, CASE_F, CASE_G); + t.assertUpper(VARIANT_E, VARIANT_E, CASE_G); + t.assertUpper(VARIANT_E, CASE_F, CASE_G); - for (c in classes) assertUpper(c, NULL, c); + for (c in classes) t.assertUpper(c, NULL, c); N(I32, BOOL); N(I32, CLASS_X); @@ -369,24 +415,24 @@ def testUpper() { // N(CLASS_X, VAR_V); // N(PARAM_P, VAR_V); - assertUpperTuple(VOID, VOID, VOID); - assertUpperTuple(null, I32, I64); - assertUpperTuple(CLASS_A, CLASS_A, CLASS_B); - assertUpperTuple(CLASS_A, CLASS_A, CLASS_C); - assertUpperTuple(CLASS_A, CLASS_B, CLASS_C); - assertUpperTuple(null, CLASS_X, CLASS_A); + t.assertUpperTuple(VOID, VOID, VOID); + t.assertUpperTuple(null, I32, I64); + t.assertUpperTuple(CLASS_A, CLASS_A, CLASS_B); + t.assertUpperTuple(CLASS_A, CLASS_A, CLASS_C); + t.assertUpperTuple(CLASS_A, CLASS_B, CLASS_C); + t.assertUpperTuple(null, CLASS_X, CLASS_A); // upper, lower, a, b - assertUpperFunction(VOID, VOID, VOID, VOID); - assertUpperFunction(null, null, I32, I64); - assertUpperFunction(CLASS_A, CLASS_B, CLASS_A, CLASS_B); - assertUpperFunction(CLASS_A, CLASS_C, CLASS_A, CLASS_C); - assertUpperFunction(CLASS_A, null, CLASS_B, CLASS_C); - assertUpperFunction(null, null, CLASS_X, CLASS_A); + t.assertUpperFunction(VOID, VOID, VOID, VOID); + t.assertUpperFunction(null, null, I32, I64); + t.assertUpperFunction(CLASS_A, CLASS_B, CLASS_A, CLASS_B); + t.assertUpperFunction(CLASS_A, CLASS_C, CLASS_A, CLASS_C); + t.assertUpperFunction(CLASS_A, null, CLASS_B, CLASS_C); + t.assertUpperFunction(null, null, CLASS_X, CLASS_A); // parameterized class types - assertUpper(CLASS_Y_P, CLASS_Z_P, CLASS_Y_P); - assertUpper(CLASS_Y_Q, CLASS_Z_Q, CLASS_Y_Q); + t.assertUpper(CLASS_Y_P, CLASS_Z_P, CLASS_Y_P); + t.assertUpper(CLASS_Y_Q, CLASS_Z_Q, CLASS_Y_Q); N(CLASS_Y_Q, CLASS_Z_P); N(CLASS_Y_P, CLASS_Z_Q); N(CLASS_Z_Q, CLASS_Y_P); @@ -396,31 +442,27 @@ def testUpper() { N(CLASS_Y_Q, CLASS_Y_P); N(CLASS_Y_P, CLASS_Y_Q); } -def testWiden() { + +def testWiden(t: TypeSystemTester) { // TODO } -def testCommonSuperClass() { + +def testCommonSuperClass(t: TypeSystemTester) { // TODO } -def testUnify() { + +def testUnify(t: TypeSystemTester) { // TODO } -def testUnifyWiden() { + +def testUnifyWiden(t: TypeSystemTester) { // TODO } -def assertTypeQuery(castOp: TypeQuery, a: Type, b: Type) { - var t = TypeSystem.newTypeQuery(a, b); - if (t != castOp) { - var buf = StringBuilder.new(); - buf.put2("expected newTypeQuery(%q, %q) = ", a.render, b.render) - .put2("%s, got %s", castOp.name, t.name); - error(buf.toString()); - } -} -def testNewTypeQuery() { - def Y = assertTypeQuery(TypeQuery.TRUE, _, _); - def N = assertTypeQuery(TypeQuery.FALSE, _, _); - def M = assertTypeQuery(TypeQuery.UNKNOWN_QUERY, _, _); + +def testNewTypeQuery(t: TypeSystemTester) { + def Y = t.assertTypeQuery(TypeQuery.TRUE, _, _); + def N = t.assertTypeQuery(TypeQuery.FALSE, _, _); + def M = t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, _, _); for (p in prim) { Y(p, p); for (q in some) { @@ -434,21 +476,21 @@ def testNewTypeQuery() { N(NULL, c); M(PARAM_P, c); M(c, PARAM_Q); - assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, c, c); + t.assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, c, c); } var A = CLASS_A, B = CLASS_B, C = CLASS_C, X = CLASS_X; - assertTypeQuery(TypeQuery.CLASS_QUERY, A, B); - assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, B, A); - assertTypeQuery(TypeQuery.FALSE, B, C); - assertTypeQuery(TypeQuery.FALSE, A, X); - assertTypeQuery(TypeQuery.FALSE, X, A); + t.assertTypeQuery(TypeQuery.CLASS_QUERY, A, B); + t.assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, B, A); + t.assertTypeQuery(TypeQuery.FALSE, B, C); + t.assertTypeQuery(TypeQuery.FALSE, A, X); + t.assertTypeQuery(TypeQuery.FALSE, X, A); var E = VARIANT_E, F = CASE_F, G = CASE_G; - assertTypeQuery(TypeQuery.VARIANT_QUERY, E, F); - assertTypeQuery(TypeQuery.TRUE, F, E); - assertTypeQuery(TypeQuery.FALSE, F, G); - assertTypeQuery(TypeQuery.FALSE, A, F); - assertTypeQuery(TypeQuery.FALSE, E, A); + t.assertTypeQuery(TypeQuery.VARIANT_QUERY, E, F); + t.assertTypeQuery(TypeQuery.TRUE, F, E); + t.assertTypeQuery(TypeQuery.FALSE, F, G); + t.assertTypeQuery(TypeQuery.FALSE, A, F); + t.assertTypeQuery(TypeQuery.FALSE, E, A); N(t2(A, A), t2(A, X)); N(t2(A, A), t2(X, A)); @@ -460,14 +502,14 @@ def testNewTypeQuery() { N(t3(A, A, A), t2(A, A)); N(t2(A, A), t3(A, A, A)); - assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, A), t2(A, B)); - assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, A), t2(B, B)); - assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, B), t2(B, B)); + t.assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, A), t2(A, B)); + t.assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, A), t2(B, B)); + t.assertTypeQuery(TypeQuery.TUPLE_QUERY, t2(A, B), t2(B, B)); def aOf = V3Array.newType; def AA = aOf(A), AB = aOf(B), AX = aOf(X); - assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, AA, AA); + t.assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, AA, AA); N(AA, AB); N(AB, AA); N(AX, AA); @@ -476,43 +518,35 @@ def testNewTypeQuery() { // parameterized class types var Y_P = CLASS_Y_P, Y_Q = CLASS_Y_Q, Z_P = CLASS_Z_P, Z_Q = CLASS_Z_Q; - assertTypeQuery(TypeQuery.CLASS_QUERY, Y_P, Z_P); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_P, Z_Q); - assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, Z_P, Y_P); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_Q, Y_P); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_P, Y_Q); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_Q, Y_P); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_P, Z_Q); - assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_Q, Z_P); - assertTypeQuery(TypeQuery.FALSE, Y_P, C); - assertTypeQuery(TypeQuery.FALSE, Y_Q, X); - assertTypeQuery(TypeQuery.FALSE, X, Y_P); - -} -def assertTypeCast(castOp: TypeCast, a: Type, b: Type) { - var t = TypeSystem.newTypeCast(a, b); - if (t != castOp) { - var buf = StringBuilder.new(); - buf.put2("expected newTypeCast(%q, %q) = ", a.render, b.render) - .put2("%s, got %s", castOp.name, t.name); - error(buf.toString()); - } -} -def testNewTypeCast() { - def Y = assertTypeCast(TypeCast.TRUE, _, _); - def N = assertTypeCast(TypeCast.THROW, _, _); - def M = assertTypeCast(TypeCast.UNKNOWN_CAST, _, _); - def T = assertTypeCast(TypeCast.TUPLE_CAST, _, _); + t.assertTypeQuery(TypeQuery.CLASS_QUERY, Y_P, Z_P); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_P, Z_Q); + t.assertTypeQuery(TypeQuery.TRUE_IF_NOT_NULL, Z_P, Y_P); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_Q, Y_P); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_P, Y_Q); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Y_Q, Y_P); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_P, Z_Q); + t.assertTypeQuery(TypeQuery.UNKNOWN_QUERY, Z_Q, Z_P); + t.assertTypeQuery(TypeQuery.FALSE, Y_P, C); + t.assertTypeQuery(TypeQuery.FALSE, Y_Q, X); + t.assertTypeQuery(TypeQuery.FALSE, X, Y_P); + +} +def testNewTypeCast(t: TypeSystemTester) { + def Y = t.assertTypeCast(TypeCast.TRUE, _, _); + def N = t.assertTypeCast(TypeCast.THROW, _, _); + def M = t.assertTypeCast(TypeCast.UNKNOWN_CAST, _, _); + def T = t.assertTypeCast(TypeCast.TUPLE_CAST, _, _); for (p in prim) { Y(p, p); - assertTypeCast(TypeCast.THROW, p, Void.TYPE); + t.assertTypeCast(TypeCast.THROW, p, Void.TYPE); } var ints = [I32, I64]; + var tt = t; for (t in ints) { for (u in ints) { if (t == u) Y(t, u); - else if (t.width < u.width) assertTypeCast(TypeCast.INT_VIEW_I, t, u); - else assertTypeCast(TypeCast.INT_CAST_I, t, u); + else if (t.width < u.width) tt.assertTypeCast(TypeCast.INT_VIEW_I, t, u); + else tt.assertTypeCast(TypeCast.INT_CAST_I, t, u); } } for (c in classes) { @@ -521,21 +555,21 @@ def testNewTypeCast() { Y(NULL, c); M(PARAM_P, c); M(c, PARAM_Q); - assertTypeCast(TypeCast.THROW, c, Void.TYPE); + t.assertTypeCast(TypeCast.THROW, c, Void.TYPE); } var A = CLASS_A, B = CLASS_B, C = CLASS_C, X = CLASS_X; - assertTypeCast(TypeCast.CLASS_CAST, A, B); - assertTypeCast(TypeCast.TRUE, B, A); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, B, C); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, A, X); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, X, A); + t.assertTypeCast(TypeCast.CLASS_CAST, A, B); + t.assertTypeCast(TypeCast.TRUE, B, A); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, B, C); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, A, X); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, X, A); var E = VARIANT_E, F = CASE_F, G = CASE_G; - assertTypeCast(TypeCast.VARIANT_CAST, E, F); - assertTypeCast(TypeCast.TRUE, F, E); - assertTypeCast(TypeCast.THROW, F, G); - assertTypeCast(TypeCast.THROW, A, F); - assertTypeCast(TypeCast.THROW, E, A); + t.assertTypeCast(TypeCast.VARIANT_CAST, E, F); + t.assertTypeCast(TypeCast.TRUE, F, E); + t.assertTypeCast(TypeCast.THROW, F, G); + t.assertTypeCast(TypeCast.THROW, A, F); + t.assertTypeCast(TypeCast.THROW, E, A); T(t2(A, A), t2(A, X)); T(t2(A, A), t2(X, A)); @@ -547,9 +581,9 @@ def testNewTypeCast() { N(t3(A, A, A), t2(A, A)); N(t2(A, A), t3(A, A, A)); - assertTypeCast(TypeCast.TUPLE_CAST, t2(A, A), t2(A, B)); - assertTypeCast(TypeCast.TUPLE_CAST, t2(A, A), t2(B, B)); - assertTypeCast(TypeCast.TUPLE_CAST, t2(A, B), t2(B, B)); + t.assertTypeCast(TypeCast.TUPLE_CAST, t2(A, A), t2(A, B)); + t.assertTypeCast(TypeCast.TUPLE_CAST, t2(A, A), t2(B, B)); + t.assertTypeCast(TypeCast.TUPLE_CAST, t2(A, B), t2(B, B)); def aOf = V3Array.newType; def AA = aOf(A), AB = aOf(B), AX = aOf(X); @@ -563,22 +597,22 @@ def testNewTypeCast() { // parameterized class types var Y_P = CLASS_Y_P, Y_Q = CLASS_Y_Q, Z_P = CLASS_Z_P, Z_Q = CLASS_Z_Q; - assertTypeCast(TypeCast.CLASS_CAST, Y_P, Z_P); - assertTypeCast(TypeCast.UNKNOWN_CAST, Y_P, Z_Q); - assertTypeCast(TypeCast.TRUE, Z_P, Y_P); - assertTypeCast(TypeCast.UNKNOWN_CAST, Z_Q, Y_P); - assertTypeCast(TypeCast.UNKNOWN_CAST, Y_P, Y_Q); - assertTypeCast(TypeCast.UNKNOWN_CAST, Y_Q, Y_P); - assertTypeCast(TypeCast.UNKNOWN_CAST, Z_P, Z_Q); - assertTypeCast(TypeCast.UNKNOWN_CAST, Z_Q, Z_P); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, Y_P, C); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, Y_Q, X); - assertTypeCast(TypeCast.THROW_IF_NOT_NULL, X, Y_P); -} -def assertMaybeEqual = assertRelation(TypeSystem.maybeEqual, "maybe equal", _, _, _); -def testMaybeEqual() { - def Y = assertMaybeEqual(true, _, _); - def N = assertMaybeEqual(false, _, _); + t.assertTypeCast(TypeCast.CLASS_CAST, Y_P, Z_P); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Y_P, Z_Q); + t.assertTypeCast(TypeCast.TRUE, Z_P, Y_P); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Z_Q, Y_P); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Y_P, Y_Q); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Y_Q, Y_P); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Z_P, Z_Q); + t.assertTypeCast(TypeCast.UNKNOWN_CAST, Z_Q, Z_P); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, Y_P, C); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, Y_Q, X); + t.assertTypeCast(TypeCast.THROW_IF_NOT_NULL, X, Y_P); +} + +def testMaybeEqual(t: TypeSystemTester) { + def Y = t.assertMaybeEqual(true, _, _); + def N = t.assertMaybeEqual(false, _, _); for (p in some) { Y(p, p); Y(PARAM_P, p); @@ -603,9 +637,10 @@ def testMaybeEqual() { N(fAV, fBV); N(fVA, fBV); + var tt = t; for (t in some) { for (u in some) { - assertMaybeEqual(t == u, t2(t, u), t2(t, t)); + tt.assertMaybeEqual(t == u, t2(t, u), t2(t, t)); Y(t2(t, u), t2(t, VAR_V)); Y(t2(u, t), t2(VAR_V, t)); } @@ -625,43 +660,27 @@ def testMaybeEqual() { } } -def assertWiden(expected: Type, a: Type, b: Type) { - var got = TypeSystem.widen(a, b); - if (expected != got) { - var buf = StringBuilder.new(); - buf.put2("expected TypeSystem.widen(%q, %q) == ", a.render, b.render); - if (expected == null) buf.puts(""); - else expected.render(buf); - buf.puts(", got "); - if (got == null) buf.puts(""); - else got.render(buf); - error(buf.toString()); - } - var g2 = TypeSystem.widen(b, a); - if (g2 != got) { - var buf = StringBuilder.new(); - buf.put2("TypeSystem.widen(%q, %q) is not commutative", a.render, b.render); - error(buf.toString()); - } -} +def testFloats(t: TypeSystemTester) { + def Y = t.assertImplicit(true, _, _); + def N = t.assertImplicit(false, _, _); + def W = t.assertWiden; -def testFloats() { - assertImplicit(true, FLOAT, DOUBLE); - assertImplicit(false, DOUBLE, FLOAT); - assertImplicit(true, Byte.TYPE, FLOAT); + Y(FLOAT, DOUBLE); + N(DOUBLE, FLOAT); + Y(Byte.TYPE, FLOAT); for (i = 1; i <= 64; i++) { - assertImplicit(i < 25, Int.getType(false, i), FLOAT); - assertImplicit(i < 24, Int.getType(true, i), FLOAT); - assertImplicit(i < 54, Int.getType(false, i), DOUBLE); - assertImplicit(i < 53, Int.getType(true, i), DOUBLE); + t.assertImplicit(i < 25, Int.getType(false, i), FLOAT); + t.assertImplicit(i < 24, Int.getType(true, i), FLOAT); + t.assertImplicit(i < 54, Int.getType(false, i), DOUBLE); + t.assertImplicit(i < 53, Int.getType(true, i), DOUBLE); } - assertWiden(DOUBLE, FLOAT, DOUBLE); - assertWiden(null, FLOAT, NULL); - assertWiden(null, DOUBLE, BOOL); - assertWiden(null, DOUBLE, VOID); + W(DOUBLE, FLOAT, DOUBLE); + W(null, FLOAT, NULL); + W(null, DOUBLE, BOOL); + W(null, DOUBLE, VOID); - assertWiden(FLOAT, Byte.TYPE, FLOAT); - assertWiden(DOUBLE, Int.TYPE, DOUBLE); + W(FLOAT, Byte.TYPE, FLOAT); + W(DOUBLE, Int.TYPE, DOUBLE); } diff --git a/aeneas/test/TypeTest.v3 b/aeneas/test/TypeTest.v3 index 44926207d..3384a8851 100644 --- a/aeneas/test/TypeTest.v3 +++ b/aeneas/test/TypeTest.v3 @@ -1,45 +1,46 @@ -def TEST = UnitTest.new("Type", test); +def T = UnitTests.registerT("type:", _, TypeTester.new, _); +def X_ = void( // XXX: more internal tests for Type + T("int", test_int), + T("named", test_named), + () +); -def error = System.error("TestError", _); +private class TypeTester(t: Tester) { + def buf = StringBuilder.new(); -def assertString(expected: string, got: string) { - if (!Arrays.equal(expected, got)) error(Strings.format2("expected \"%s\", got \"%s\"", expected, got)); -} - -def assertBuffer(expected: string, buf: StringBuilder) { - var ok = buf.length == expected.length; - if (ok) { - for (i < expected.length) { - if (buf.buf[i] != expected[i]) { - ok = false; - break; + def assertString(expected: string, got: string) { + if (!Arrays.equal(expected, got)) t.fail2("expected \"%s\", got \"%s\"", expected, got); + } + def assertBuffer(expected: string, buf: StringBuilder) { + var ok = buf.length == expected.length; + if (ok) { + for (i < expected.length) { + if (buf.buf[i] != expected[i]) { + ok = false; + break; + } } } + if (!ok) t.fail2("expected \"%s\", got \"%s\"", expected, buf.toString()); + } + def assertRender(expected: string, render: StringBuilder -> StringBuilder) { + assertBuffer(expected, render(buf.reset())); } - if (!ok) error(Strings.format2("expected \"%s\", got \"%s\"", expected, buf.toString())); } -def buf = StringBuilder.new(); -def assertRender(expected: string, render: StringBuilder -> StringBuilder) { - assertBuffer(expected, render(buf.reset())); +def test_int(t: TypeTester) { + t.assertRender("int", Int.TYPE.render); + var f = Function.newType(Int.TYPE, Int.TYPE); + t.assertRender("int -> int", f.render); + t.assertRender("(int -> int) -> int", Function.newType(f, Int.TYPE).render); + t.assertRender("int -> int -> int", Function.newType(Int.TYPE, f).render); } -def test() { - // TODO: more internal tests for Type - { - assertRender("int", Int.TYPE.render); - var f = Function.newType(Int.TYPE, Int.TYPE); - assertRender("int -> int", f.render); - assertRender("(int -> int) -> int", Function.newType(f, Int.TYPE).render); - assertRender("int -> int -> int", Function.newType(Int.TYPE, f).render); - } - - { - var ir = NamedTypeRef.new(null, Token.new("f", "int", 0, 0), null); - assertRender("int", ir.render); - var f = FuncTypeRef.new(ir, ir); - assertRender("int -> int", f.render); - assertRender("(int -> int) -> int", FuncTypeRef.new(f, ir).render); - assertRender("int -> int -> int", FuncTypeRef.new(ir, f).render); - } +def test_named(t: TypeTester) { + var ir = NamedTypeRef.new(null, Token.new("f", "int", 0, 0), null); + t.assertRender("int", ir.render); + var f = FuncTypeRef.new(ir, ir); + t.assertRender("int -> int", f.render); + t.assertRender("(int -> int) -> int", FuncTypeRef.new(f, ir).render); + t.assertRender("int -> int -> int", FuncTypeRef.new(ir, f).render); } \ No newline at end of file