RFR: 8268312: Compilation error with nested generic functional interface

Maurizio Cimadamore mcimadamore at openjdk.java.net
Tue Sep 28 17:26:38 UTC 2021

On Mon, 20 Sep 2021 19:00:29 GMT, Vicente Romero <vromero at openjdk.org> wrote:

> Please review this PR, which is my proposal to fix an existing regression. This code:
> import java.util.Optional;
> class App {
>     public static void main(String[] args) {
>         Optional.of("").map(outer -> {
>             Optional.of("")
>                 .map(inner -> returnGeneric(outer))
>                 .ifPresent(String::toString);
>             return "";
>         });
>     }
>     private static <RG> RG returnGeneric(RG generic) {
>         return generic;
>     }
> }
> is not accepted by javac but if the user passes the `-Xdiags:verbose` option then the code compiles. I tracked down the reason for this puzzling difference and I found that it is due to our diagnostic rewriters which can generate more detailed positions for error messages but in cases like the one above can trick the compiler to generate an error message too early. The code deciding if an error message should be deferred or not, depending on the position, is at `DeferredDiagnosticHandler::report`. We decide to do the rewriting if we are in diagnostics compact mode, this is why the error doesn't occur with the `-Xdiags:verbose` option. This fix will made some diagnostics to appear at a slightly different position, but won't make the compiler reject correct code. Comments?

Very tricky issue. Basically, the deferred diagnostic handler checks whether the diagnostic is associated with the tree being speculatively attributed. This is required, because sometimes, when attributing a piece of code, we could have completion events, causing the compiler to jump from one file to another - it is important that completion related issues are logged, even if we're inside deferred attribution, which is why the logic is there.

The resolution diagnostic rewrite throws a spanner in the work though - because it can sometime update the diagnostic position to make it appear like the error was on an outermost node, which then will fall outside the tree covered by the deferred diagnostic handler, and result in spurious errors being generated.

I think a more robust solution would be to leave the diagnostic as is (since the diagnostic handler in DeferredAttr depends on it), but at the same time, maybe record something on the JCDiagnostic object - e.g. like a Supplier<JCDiagnostic> which allows the diagnostic to be simplified later, by `Log`, rather than eagerly, by `Resolve`. It is possible that, if we do this, we might no longer require a COMPRESSED flag on the diagnostic at all - after all, if Log is in charge of the rewriting, it knows which diagnostics have been touched.


PR: https://git.openjdk.java.net/jdk/pull/5586

More information about the compiler-dev mailing list