RFR: 8338301: Error recovery and reporting should be improved for erroneous implicitly declared classes

Jan Lahoda jlahoda at openjdk.org
Thu Aug 15 08:46:17 UTC 2024


Consider code like:

$ cat /tmp/M.java 
main() {}


which is compiled like:

$ javac --enable-preview --source 24 /tmp/M.java 
/tmp/M.java:1: error: class, interface, enum, or record expected
main() {}
^
1 error


This error is problematic for two reasons:
 - this is clearly a method with missing return type, but the error recovery does not see it as such
 - with implicitly declared classes, not only classes/interfaces/enum/records are expected here, but also methods and fields as permitted

Note that if a method inside a class is missing a return type, the error is much better, so this is a problem specifically for methods on the top-level:

$ cat /tmp/C.java
public class C {
    main() {}
}
$ javac --enable-preview --source 24 /tmp/C.java 
/tmp/C.java:2: error: invalid method declaration; return type required
    main() {}
    ^
1 error


The immediate reason is that the javac's parser will speculatively parse the code to see if the code looks-like a method or a field, but this speculative parse does not special-case methods without return types (unlike class-member parsing, which has this special case, partly because of constructors).

I tried to remove this speculative parsing, reusing the code to parse class members, but I wasn't successful in that, sadly.

So, the proposal here is three-fold:
 - the speculative parse will special-case methods without return type, as member parsing does
 - when the parser cannot figure out the at the top-level code, the error will be "class, interface, annotation type, enum, record, method or field expected", instead of the current "class, interface, enum, or record expected", to cover all possibilities. (This is only when implicitly declared classes are permitted, i.e. when preview is enabled and source level is correct, otherwise the existing error will be emitted. The idea here is not to suggest something that will lead to another compile-time error.)
 - (definite) statements at the top-level are special-cased, similarly to how they are special-cased for members after https://github.com/openjdk/jdk/pull/20526

With this patch, errors like this are produced:

$ cat /tmp/M.java 
main() {}
$ javac --enable-preview -source 24 /tmp/M.java 
/tmp/M.java:1: error: invalid method declaration; return type required
main() {}
^
Note: /tmp/M.java uses preview features of Java SE 24.
Note: Recompile with -Xlint:preview for details.
1 error



$ cat /tmp/S.java 
if (true);
$ javac --enable-preview -source 24 /tmp/S.java 
/tmp/S.java:1: error: statements not expected outside of methods and initializers
if (true);
^
1 error



$ cat /tmp/L.java 
"not-handled"
$ javac --enable-preview -source 24 /tmp/L.java 
/tmp/L.java:1: error: class, interface, annotation type, enum, record, method or field expected
"not-handled"
^
1 error

-------------

Commit messages:
 - Cleanup.
 - Merge branch 'master' into JDK-8338301
 - Cleanup.
 - Handling semicolons.
 - 8338301: Error recovery and reporting should be improved for erroneous implicitly declared classes
 - Adding a comment for the isDefiniteStatementStartToken.
 - Cleanup.
 - Cleanup/reducing scope
 - Fixing tests.
 - 8337976: Insufficient error recovery in parser for switch inside class body, and missing name in parameterized type

Changes: https://git.openjdk.org/jdk/pull/20591/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=20591&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8338301
  Stats: 278 lines in 4 files changed: 276 ins; 0 del; 2 mod
  Patch: https://git.openjdk.org/jdk/pull/20591.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/20591/head:pull/20591

PR: https://git.openjdk.org/jdk/pull/20591


More information about the compiler-dev mailing list