Lambdas do not copy over SYNTHETIC flag for local variables
Arnold Alejo Nunag
arnoldnunag12 at gmail.com
Sat Nov 8 21:41:15 UTC 2025
Hello,
A project which I help out with recently discovered a bug with regards
to lambdas; specifically, local variables within lambdas (or more
specifically, their synthetic generated methods) never have the
SYNTHETIC flag, even if the same source outside of a lambda would emit
local variables with the SYNTHETIC flag. The bug occurs on openjdk
version "25.0.1" 2025-10-21 LTS.
Examples of source that emit SYNTHETIC-marked local variables are
enhanced-for loops operating on arrays, and (what prompted our
discovery) pattern-matching instanceof.
I tested the same bug on Java 17 (17.0.14) and 21 (21.0.9), and it
occurs for the pattern-matching instanceof. Interesting, testing with an
array enhanced-for shows that the bug occurs only on 25, but not for 21,
17, or 8.
This bug originates from
https://git.openjdk.org/jdk/commit/cf30c203379008ebae37bf00f1839a69cd53ca26
and
https://git.openjdk.org/jdk/commit/360461f13671495c07ab9881284f24191ecc3525,
where only the FINAL flag is copied over for local variables when
translating code for lambdas.
The following source when disassembled demonstrates the problem:
/// BEGIN SOURCE
public class Test {
private void test_noLambda() {
if (getThing() instanceof Number number) {
System.out.println(number);
}
}
private void test_withLambda() {
Runnable run = () -> {
if (getThing() instanceof Number number) {
System.out.println(number);
}
};
}
private Object getThing() {
return null;
}
}
/// END SOURCE
1. Compile the above class using `javac -g:vars Test.java`.
2. Run `javap -p -c -l Test.class`.
The expected result is that both `test_noLambda` and
`lambda$test_withLambda$0` should have the same local variable table
with two slots: `number` and `this`.
The actual result is that `lambda$test_withLambda$0` has one extra local
variable: `patt0$temp`. As the name implies, that belongs to the
pattern-matching instanceof.
I have found a potential fix through the following patch (though I have
not yet fully tested this):
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index b13c9e0fe2b..41554dae432 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -1152,7 +1152,7 @@ VarSymbol translate(final VarSymbol sym, LambdaSymbolKind skind) {
propagateAnnos = false;
break;
case LOCAL_VAR:
- ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
+ ret = new VarSymbol(sym.flags() & (SYNTHETIC | FINAL), sym.name, sym.type, translatedSym);
ret.pos = sym.pos;
// If sym.data == ElementKind.EXCEPTION_PARAMETER,
// set ret.data = ElementKind.EXCEPTION_PARAMETER too.
I'd like to contribute the above fix myself, if possible. I've already
submitted my OCA (pending approval). I believe my next step is to file a
bug through https://bugs.java/, which I'll do within a few days (or if
someone tells me to).
Thank you!
~ Arnold Alejo Nunag, @sciwhiz12
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20251109/3cf08182/attachment.htm>
More information about the compiler-dev
mailing list