RFR: 8373570: Javac stack overflow on method-local class with nested record referring to enclosing type

Maurizio Cimadamore mcimadamore at openjdk.org
Mon Dec 15 11:12:47 UTC 2025


On Mon, 15 Dec 2025 11:04:00 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

>> The fix for https://git.openjdk.org/jdk/pull/21410 introduced a regression: javac will no longer reject local classes created from a context that is not an inner class of the class enclosing the local class.
>> 
>> In other words, javac is failing to apply this restriction in the JLS (15.9.2):
>> 
>>> If U is not an inner class of O or O itself, then a compile-time error occurs
>> 
>> The issue is causes by the new method `Resolve::findLocalClassOwner`. This method is meant to start at the point where the local class is instantiated, and walk up the enclosing scopes, until it finds the place where the local class is defined. If any static context has been traversed doing this search, an error is issued.
>> 
>> Unfortunately, neither static local classes, nor records/interfaces count as "static contexts" in the javac implementation -- that is, they do not increase the "static" counter in the `env.info` variable.
>> 
>> Instead, most code in `Resolve` does this (see e.g. `Resolve::findFun`):
>> 
>> 
>> while (env1.outer != null) {
>>     if (isStatic(env1)) staticOnly = true;
>>     ...
>>     if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
>>     env1 = env1.outer;
>> }
>> 
>> 
>> The new method acts a bit differently, and it's missing the logic to check the staticness of the enclosing class, hence the regression.
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java line 3852:
> 
>> 3850:                     new BadLocalClassCreation(c) :
>> 3851:                     owner;
>> 3852:             } else if (isStatic(env1) || env1.enclClass.sym.isStatic()) {
> 
> In other similar loops, we would check `isStatic` as the first statement in the loop. However, here we can't do that -- if the local class is static, it will be defined in a static method -- this means the search will always end with a static context. But this is ok, and we don't want to raise an error!

See tests `staticLocal` and `staticLocalFromAnon` (these were derived from some failing code in the Stream API).

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

PR Review Comment: https://git.openjdk.org/jdk/pull/28821#discussion_r2618969439


More information about the compiler-dev mailing list