google / j2cl

Java to Closure JavaScript transpiler
Apache License 2.0
1.23k stars 144 forks source link

Cannot compile a lambda expression referencing itself. #123

Closed arenevier closed 3 years ago

arenevier commented 3 years ago

To Reproduce This code will not build with j2cl

import elemental2.dom.EventListener;
import elemental2.dom.Event;

...

public class Foo() {
  private final EventListener mEventListener;
  public Foo() {
      mEventListener = (event) -> {
        document.body.removeEventListener(
            "mousedown", mEventListener);
      };
     document.body.addEventListener("mousedown", mEventListener);
  }

The error will be: The blank final field mEventListener may not have been initialized

This pattern builds fine with java (openjdk 1.8). It also works with gwt 2.8.2, but fails to compile with gwt 2.9.0

Workarounds: use an anonymous class to define mEventListener. Or make it non final.

rluble commented 3 years ago

The code gives the same error "variable runnable might not have been initialized" in jdk 11.

Because the lambda is constructed before the assignment to the field/variable is made there is some ambiguity.

When the destination is a field then due to the way lambdas/inner classes capture outer fields it does work (lambdas and inner classes capture the enclosing instance and reference the field through that instance).

If the destination was a local variable then the use would happen before the assignment so you cannot write Runnable r = () -> r.run(); either

Java (java 11) treats the final field in the same way as the variable with respect of error reporting and give an error in this situation. j2cl relies on the frontend so it is working as intended.