We evaluated the correctness of Polyglot by testing it against the Jacks test suite. Polyglot fails 207 test cases out of 4863 in the test suite. 40 of the failed test cases involve an ambiguity in the JLS that Polyglot chose to resolve differently from Jacks's expectation. 90 of the failed test cases either contradict the JLS, or test features of the compiler other than its language implementation. 15 of the failed test cases are outside the control of Polyglot.
Excluding such anomalous test cases, Polyglot passes 98.7% (4656/4718) of the Jacks tests. For comparison using the same criteria, javac (1.7.0) passes 99.2% of the Jacks tests.
We have classified the failed 207 test cases as follows.
-
Noncompliance with JLS (62 test cases):
-
A field may not be accessed from an anonymous class in an explicit constructor invocation. (1 test case) + Show sample code...
class T8851e3 { static class Top { int x; class Dummy { Dummy(Object o) {} } class Inside extends Dummy { Inside() { super(new Object() { int r = x; }); // error } } } }
-
Explicit constructors may reference qualified this or super which names an enclosing class. Polyglot requires that arguments to explicit constructor invocations be in a static content. (1 test case) + Show sample code...
class T8851q17 { T8851q17(Object o) {} } class T8851q17a { class Middle extends T8851q17 { Middle(int i) { super(null); } Middle() { // Here, the innermost instance of T8851q17a to enclose // new Middle is T8851q17a.this super(new Middle(1).new Inner() {}); } class Inner {} } }
-
A constructor with private accessibility can be accessed from a static anonymous class defined inside the same class. However, there is no enclosing class for the superclass. (1 test case) + Show sample code...
class T887adci26 { T887adci26(Object o) {} { class A { private A() {} } class B extends T887adci26 { B() { super(new A() {}); } } } }
-
Blank final instance variables must be assigned by the end of every constructor. Even if the constructor loops, Polyglot still requires that final fields be initialized. (1 test case) + Show sample code...
class T8312f22 { final int i; T8312f22() { while (true); } }
-
An instance variable initializer may not complete abruptly with a checked exception, unless all constructors have a compatible throws clause. (2 test cases) + Show sample code...
class T832a3 { int m() throws ClassNotFoundException { return 1; } int i = m(); T832a3() throws ClassNotFoundException {} }
-
An instance variable initializer may not complete abruptly with a checked exception, unless all constructors have a compatible throws clause; the generated constructor in an anonymous class always has the right throws clause. (5 test cases) + Show sample code...
try { new Object() { int m() throws ClassNotFoundException { return 1; } int i = m(); }; } catch (ClassNotFoundException e) { }
-
It is a compile-time error if a static class contains a usage of a non-static member of the enclosing class. (1 test case) + Show sample code...
class T852nsmu4 { class C {} static class T852nsmu4_Test { C c; } }
-
A static member type may use private non-static members of a superclass that happens to be the enclosing class. (1 test case) + Show sample code...
class T852ainsmu5 { private class C {} static class T852ainsmu5_Test extends T852ainsmu5 { { new C(); } } }
-
Polyglot uses a more precise definite assignment on ternary expressions (conditionals), accepting programs that should be rejected according to JLS. (15 test cases) + Show sample code...
final int x; int ia[] = {0}; ia[false ? x = 0 : 0] += x = 0;
-
Polyglot uses a more precise definite assignment on if statements, accepting programs that should be rejected according to JLS. (1 test case) + Show sample code...
public class T1627f4 { final int val = 0; T1627f4() { if (false) { val = 1; } } }
-
Combined with 16.6-8, v is DA before members of a local class if v is DA before the local class declaration. (1 test case) + Show sample code...
final int i; class Local { class Member { { new Object() { // anonymous int j = i; }; } } } i = 1; new Local().new Member();
-
A blank final may be assigned in different block statement groups, provided it not assigned twice. However, a variable initialized with a constant is inlined, and is not a blank final. (2 test cases) + Show sample code...
case 0: final byte b = 0; break; case 1: byte c = b;
-
The ASCII SUB character (0x1a) should be ignored if it is the last character in the escaped stream. (2 test cases)
-
Failures related to rounding and equality of floating point values. (6 test cases)
-
Failures related to unicode escapes. (1 test case)
-
A qualified type name must refer to a single accessible member type of the qualifying type, or an error occurs. [Polyglot ignores the specified type qualifier after name resolution, which fails type checking that occurs later on.] (4 test cases) + Show sample code...
package p1; class T6552t5a { class C {} } interface T6552t5b { class C {} } public class T6552t5c extends T6552t5a implements T6552t5b {} ----- class T6552t5d extends p1.T6552t5c { // only the accessible T6552t5b.C is inherited T6552t5d.C t; }
-
A simple type name favors a visible local class declaration over member types. [Polyglot detects an infinite loop in the scheduler.] (1 test case) + Show sample code...
class C { static final int i = 1; } new Object() { void foo(int j) { class C { static final int i = 2; } switch (j) { case 0: case 1: // C refers to the innermost local class, since it shadows // the other version, hence C.i is 2 case C.i: } } };
-
Polyglot uses a more precise definite assignment on assert statements, accepting programs that should be rejected according to JSR 41.4. (6 test cases) + Show sample code...
final boolean b = true; // constant assert true : b = true;
-
V is DU after the assert iff V is DU after Expression1 when true and V is DU before the assert. (4 test cases) + Show sample code...
final boolean b; boolean b1 = true; assert b1 : b = true; b = true;
-
Final variables must not be multiply assigned in loops. [Polyglot rejects programs in this category.] (6 test cases) + Show sample code...
final boolean b; while (true) assert (b = true) && false;
-
-
Inconsistencies in the JLS (18 test cases):
-
The JLS grammar does not allow names as qualifiers in qualified explicit constructor invocation, but Chapter 18 does. (2 test cases) + Show sample code...
class T8851q4 { class Inner {} } class Sub4 extends T8851q4.Inner { Sub4(T8851q4 t) { // using a parameter is legal t.super(); } }
-
The JLS grammar does not allow access to the element of an anonymous array, but Chapter 18 does. (1 test case) + Show sample code...
int i = new int[]{1}[0];
-
The JLS grammar does not allow names on the left-hand side of an assignment to be parenthesized, but Chapter 18 does. (15 test cases) + Show sample code...
int i = 1; (i) *= 1;
-
-
Lack of clarity in JLS (22 test cases):
-
A statement in the for update is reachable, even when it is not executed (this is underspecified in the JLS). (8 test cases) + Show sample code...
for (int i=0; i<10; ++i) break;
-
While not well-specified, the scope of a local class in a switch statement is the immediately enclosing switch block statement (and not the entire switch). (2 test cases) + Show sample code...
void m(int i) { switch (i) { case 0: class Local {} break; case 1: class Local {} } }
-
Reading a variable is not legal before declaration, even if it was assigned before declaration. (4 test cases) + Show sample code...
class T8323ifi7 { int i = (i = 1) + i; }
-
A blank final field may only be assigned by simple name. (5 test cases) + Show sample code...
class T16s1 { static final int i; static { T16s1.i = 1; } }
-
The JLS is missing a rule. Although 16.2.2 claims v is DA before the initializer in Local since it is DA before the declaration of Local, this is not true for a local class in a switch statement, if an instance is created where v is not DA. This is now resolved by the fact that the scope of local classes is limited to the switch block, while variables remain scoped to the entire switch statement. (1 test case) + Show sample code...
class T1623s1 { void m(int i) { switch (i) { case 0: final int j; j = 1; class Local { int k = j; } break; case 1: // Javac 1.4 compiles this, and causes a VerifyError int k = new Local().k; // Local went out of scope } } }
-
/**/ is a legal, degenerate doc comment, in spite of a bug in the grammar which doesn't allow it. (2 test cases) + Show sample code...
class T378 {/**/}
-
-
Incorrect Jacks test cases (2 test cases):
-
Anything other than type String is not a constant expression. [The JLS states otherwise.] (2 test cases) + Show sample code...
class T1528nots2 { final Object o = "1"; void foo (int j) { switch (j) { case 0: case ((o == "1") ? 1 : 0): } } }
-
-
Failures outside the control of Polyglot (15 test cases):
-
A failure caused by an error in javac during post-compilation. (Polyglot uses javac as the back end for generating bytecode.) (1 test case) + Show sample code...
class T887adci29 { Object o = new Object() { class Inner { private Inner() {} } }.new Inner(){}; }
-
javac error: A blank final may be assigned in different block statement groups, provided it not assigned twice. Even with a non-constant initializer, the variable declaration is treated as a blank final. (2 test cases) + Show sample code...
case 0: final int j = "".length(); break; case 1: j = 1;
-
Polyglot uses Java 7's toString() method to obtain the string representations of primitive values. Failures in this category are probably associated with different behaviors of toString() in different version of Java. (6 test cases) + Show sample code...
"" + 123456768f == "1.2345677E8"
-
Failures related to unexpected results of running compiled code (e.g., situations causing class initialization). (6 test cases)
-
-
Non-JLS failures (88 test cases):
-
Jacks expects the availability of -deprecation flag, not supported in Polyglot. (68 test cases)
-
Failures related to command-line arguments. (11 test cases)
-
Jacks expects the availability of -encoding flag, not supported in Polyglot. (6 test cases)
-
Failures related to loading classes from zip files. (3 test cases)
-
Updated: 11/02/2015