RFR: 8341782: Allow lambda capture of basic for() loop variables as with enhanced for()

Archie Cobbs acobbs at openjdk.org
Wed Oct 9 15:59:07 UTC 2024


On Wed, 9 Oct 2024 09:20:28 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

>> This PR changes the compiler to allow basic `for()` loop iteration variables to be captured by lambdas in the loop body, even when their "effectively final" status is invalidated by modifications in the header of the loop.
>> 
>> This allows code like this to compile:
>> 
>> for (int i = 1; i <= 3; i++) {
>>     Runnable r = () -> System.out.println(i);
>> }
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java line 3486:
> 
>> 3484:             // Collect the for() loop iteration variables with the FOR_LOOP_BODY_MAY_CAPTURE flag
>> 3485:             HashSet<VarSymbol> capturableForLoopVars = null;
>> 3486:             if (tree.init != null) {
> 
> This is a bit unfortunate. In principle, a variable has `FOR_LOOP_BODY_MAY_CAPTURE` should just be  `EFFECTIVELY_FINAL` - at least in the context of the for loop body. I suppose there's still a problem that we'd have to unset `EFFECTIVELY_FINAL` after the loop body... but I wonder, do we care? After all, we have already flow-analyzed the other for-loop parts (condition and step), so perhaps we just set `EFFECTIVELY_FINAL` before scanning the loop body, and leave it there?

We can't really mess with `EFFECTIVELY_FINAL` at all, because we need to preserve the current behavior in the init, condition, and step, so that you still get an error in this example:

for (int i = 0;
  i++ + ((IntSupplier)() -> i).getAsInt() < 3; ) {      // error - i is not effectively final
    ((IntSupplier)() -> i).getAsInt();                  // ok - i is effectively final in the body
}

Put another way, I don't see how we could avoid having two separate "effectively final" flags - one for the loop body, and the original one for everything else, at least, not without combining `AssignAnalyzer` and `CaptureAnalyzer`.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/21415#discussion_r1793776827


More information about the compiler-dev mailing list