JDK-8024809 : javac, some lambda programs are rejected by flow analysis
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-09-13
  • Updated: 2015-05-11
  • Resolved: 2013-10-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b115Fixed
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
This compiles

public class Tmp
{
    final Runnable r1 = ()->System.out.println(r1);
}

This does NOT . . . . . . . . . . . . . . . . . . . . . . . . .

public class Tmp
{
    final Runnable r1;

    final Runnable r2 = ()-> System.out.println(r1); // Error: r1 not
initialized

    Tmp()
    {
        r1 = ()->System.out.println(r1);  // Error: r1 not initialized
    }
} 

This compiles . . . . . . . . . . . . . . . . . . . . . . . . .

public class Tmp
{
    final Object lock = new Object();

    final Runnable r2 = ()->{
        System.out.println(r2);
        synchronized (lock){
        }
    };
}

This does NOT . . . . . . . . . . . . . . . . . . . . . . . . .

public class Tmp
{
    final Object lock = new Object();

    final Runnable r2 = ()->{
        synchronized (lock){
            System.out.println(r2);  // Error: self-reference in initializer
        }
    };
}


reported by Zhong Yu in lambda-dev list.
Comments
The following code doesn't produce a compilation error if ran vs jdk b132: class Tmp { final Runnable notInitialized = () -> { Runnable simpleVariable = notInitialized; }; } and this produces: class Tmp { final Runnable notInitialized = () -> { System.out.println(notInitialized); }; } It seems to me that behavior in both cases should be similar, shouldn't it?
24-07-2014

The fix for this patch will break several JCK tests, this is expected, the affected tests will need to be modified.
19-10-2013

The fix for this bug can't be pushed till the fix for JDK-8026854 is in TL
18-10-2013

The current patch for this bug breaks the build: /home/vromero/openJDK/jdk8Flow/jdk/src/share/classes/java/time/temporal/TemporalQueries.java:101: error: self-reference in initializer return temporal.query(ZONE_ID); ^ /home/vromero/openJDK/jdk8Flow/jdk/src/share/classes/java/time/temporal/TemporalQueries.java:108: error: self-reference in initializer return temporal.query(CHRONO); ^ /home/vromero/openJDK/jdk8Flow/jdk/src/share/classes/java/time/temporal/TemporalQueries.java:115: error: self-reference in initializer return temporal.query(PRECISION); ^ /home/vromero/openJDK/jdk8Flow/jdk/src/share/classes/java/time/temporal/TemporalQueries.java:124: error: illegal forward reference return (zone != null ? zone : temporal.query(OFFSET)); This is the now offending code is: static final TemporalQuery<ZoneId> ZONE_ID = (temporal) -> { return temporal.query(ZONE_ID); }; static final TemporalQuery<Chronology> CHRONO = (temporal) -> { return temporal.query(CHRONO); }; static final TemporalQuery<TemporalUnit> PRECISION = (temporal) -> { return temporal.query(PRECISION); }; static final TemporalQuery<ZoneId> ZONE = (temporal) -> { ZoneId zone = temporal.query(ZONE_ID); return (zone != null ? zone : temporal.query(OFFSET)); };
15-10-2013

Two specified errors are intertwined here. #1, 8.3.2.3: First, a "use" of a field in a field initializer is generally prohibited if the use occurs before the field declaration. The spec is not very clear on this, but the intent has always been that "before" includes the field's own initializer. So "int x = x+1;" is not a valid field declaration. The rules carve out two exceptions: i) assignment to a field before its declaration is okay; ii) a use from inside of an anonymous class is okay. There is no exception for a use inside of a lambda expression, so "Runnable r1 = ()->System.out.println(r1);" is illegal. #2, Ch. 16: Second, a blank final field must be definitely assigned before its use. Per 16.9, a use of a blank final field in another field's initializer must be preceded by an assignment to that field in some other (preceding) initializer. This explains the two errors in example #2. --- Summary evaluation: every use of 'r1' or 'r2' in these examples should be treated as an error.
30-09-2013