-
Bug
-
Resolution: Unresolved
-
P3
-
20, 21, 22, 23, 24
-
openjdk version "20-ea" 2023-03-21
OpenJDK Runtime Environment (build 20-ea+29-2280)
OpenJDK 64-Bit Server VM (build 20-ea+29-2280, mixed mode, sharing)
When we updated the preview builds on Apache Lucene's nightly runs from Java 20-ea+17 to Java 20-ea+29, one of our test classes no longer compiled: https://github.com/apache/lucene/blob/c180c5cdabed7a64783515ec3086a3f7965b8cc6/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/TestStressNRTReplication.java
I extracted the essence of this class (one method) into a new file and replaced some external packages/classes by dummy values or java.lang.Object. So please ignore if the code is "senseful", it should just show the problem, it won't run. It is only there to compile.
When compiling the attached CompileFailure.java with Java 20-ea+29, it fails like the following:
$ javac CompileFailure.java
CompileFailure.java:269: error: local variables referenced from an inner class must be final or effectively final
if (childLog != null) {
^
CompileFailure.java:271: error: local variables referenced from an inner class must be final or effectively final
childLog.write("process done; exitValue=" + exitValue + "\n");
^
CompileFailure.java:272: error: local variables referenced from an inner class must be final or effectively final
childLog.close();
^
CompileFailure.java:282: error: local variables referenced from an inner class must be final or effectively final
if (childLog != null) {
^
CompileFailure.java:289: error: local variables referenced from an inner class must be final or effectively final
+ childLog
^
5 errors
When looking at the code, "childLog" is only assigned once with an if/else statement and never changed later. Previous versions (Java 8, 11, 17, and also Java 20-ea+17) compile that file sucessfully. It can be easily tested with above command line.
To my understanding, the code is valid and the variable *is* effectively final.
As workaround you can declare the variable as final and then compilation passes.
This is a major regression, as the code looks not too complicated and patterns like this may happen more often in productive code out there (declaring variable without final and assign a value with if/else and later use it in anonymous class). I have to say, that it was not easily to reproduce with a simple 10-liner (only the if/else and the Runnable), but still this looks like a big problem.
In Apache Lucene we fixed this by adding a final before the variable: https://github.com/apache/lucene/commit/e32b95e3161cbc2abf68d6e3bb3f609ebaa5b6ea
The problem seems to be caused byJDK-8294461, which was added in build 22. That is the only commit in javac that touched the code around "effectively final". The code mentoned here does not have the described problem (as far as I understand).
I extracted the essence of this class (one method) into a new file and replaced some external packages/classes by dummy values or java.lang.Object. So please ignore if the code is "senseful", it should just show the problem, it won't run. It is only there to compile.
When compiling the attached CompileFailure.java with Java 20-ea+29, it fails like the following:
$ javac CompileFailure.java
CompileFailure.java:269: error: local variables referenced from an inner class must be final or effectively final
if (childLog != null) {
^
CompileFailure.java:271: error: local variables referenced from an inner class must be final or effectively final
childLog.write("process done; exitValue=" + exitValue + "\n");
^
CompileFailure.java:272: error: local variables referenced from an inner class must be final or effectively final
childLog.close();
^
CompileFailure.java:282: error: local variables referenced from an inner class must be final or effectively final
if (childLog != null) {
^
CompileFailure.java:289: error: local variables referenced from an inner class must be final or effectively final
+ childLog
^
5 errors
When looking at the code, "childLog" is only assigned once with an if/else statement and never changed later. Previous versions (Java 8, 11, 17, and also Java 20-ea+17) compile that file sucessfully. It can be easily tested with above command line.
To my understanding, the code is valid and the variable *is* effectively final.
As workaround you can declare the variable as final and then compilation passes.
This is a major regression, as the code looks not too complicated and patterns like this may happen more often in productive code out there (declaring variable without final and assign a value with if/else and later use it in anonymous class). I have to say, that it was not easily to reproduce with a simple 10-liner (only the if/else and the Runnable), but still this looks like a big problem.
In Apache Lucene we fixed this by adding a final before the variable: https://github.com/apache/lucene/commit/e32b95e3161cbc2abf68d6e3bb3f609ebaa5b6ea
The problem seems to be caused by
- is blocked by
-
JDK-8299861 Inconsistent handling of effectively final and blank final variables
- Open
- relates to
-
JDK-8294461 wrong effectively final determination by javac
- Resolved
-
JDK-8299849 Revert JDK-8294461: wrong effectively final determination by javac
- Closed
- links to