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