Summary: | [1.8][compiler] Compiler tolerates illegal forward reference from lambda in initializer | ||
---|---|---|---|
Product: | [Eclipse Project] JDT | Reporter: | Srikanth Sankaran <srikanth_sankaran> |
Component: | Core | Assignee: | Srikanth Sankaran <srikanth_sankaran> |
Status: | RESOLVED FIXED | QA Contact: | |
Severity: | normal | ||
Priority: | P3 | CC: | daniel_megert, jarthana, markus.kell.r, noopur_gupta |
Version: | 4.4 | ||
Target Milestone: | BETA J8 | ||
Hardware: | PC | ||
OS: | Windows 7 | ||
See Also: | https://bugs.eclipse.org/bugs/show_bug.cgi?id=433535 | ||
Whiteboard: |
Description
Srikanth Sankaran
2013-11-17 22:43:32 EST
Another example, which compiles with ECJ, but not with 8b115: ---------------------------------------------- package test.inline; interface I { I run(int s1); } class X { public static final I fi = x -> fi; } --------------------------------------------- Srikanth, I think this needs to be taken to the 335 EG. JLS7 8.3.2.3 "Restrictions on the use of Fields during Initialization" says as point 4: "C is the innermost class or interface enclosing the usage". This should be expanded to include lambda bodies, e.g.: "C is the innermost class or interface enclosing the usage, or the usage occurs inside a lambda expression that occurs inside C". The informative text later in that section confirms this intention: "The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations." In case of lambda bodies, self-references don't cause malformed initializations. Example that shows that javac only disallows unqualified access as per 8.3.2.3: public class C { // OK: Runnable qi= () -> executeAndRepost(this.qi); static Runnable qs= () -> executeAndRepost(C.qs); // javac 1.8.0-ea-b115 says: error: self-reference in initializer Runnable i= () -> executeAndRepost(i); static Runnable s= () -> executeAndRepost(s); static void executeAndRepost(Runnable r) { } } Updated the spec request: http://mail.openjdk.java.net/pipermail/lambda-spec-observers/2013-December/000623.html The problem is actually not only about self-references from the lambda body of a field initializer, but about any forward reference that is forbidden by JLS7 8.3.2.3. A better example: ---------- public class D { int v1 = value; // Error for 8.3.2.3 (good). int v2 = D.this.value; // No simple name -> no error (good). IntSupplier s1 = () -> value; // Why error? IntSupplier s2 = new IntSupplier() { @Override public int getAsInt() { return value; // No error (good). } }; int value = 42; } ---------- There's absolutely no problem with the reference in s1's initializer. The only problem is that 8.3.2.3 needs to be updated to make lambda bodies behave the same as nested class bodies. REQUEST: ======== 8.3.2.3 should get a fifth point: "- The usage is not in a lambda expression body that occurs inside c." The next sentence could also be clarified to: "It is a compile-time error if any of the five requirements above are not met for such a forward reference." ======== FWIW, this still excludes the forward reference to "VALUE" here: public static final IntConsumer c = (@A(VALUE) int x) -> {}; public static final int VALUE = 42; The plan is to conform to the present spec and reference compiler behavior and react at the right time to any changes as they happen. |