JDK-8029725 : Lambda reference to containing local class causes javac infinite recursion
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2013-12-07
  • Updated: 2014-07-29
  • Resolved: 2014-05-01
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 JDK 9
8u20 b15Fixed 9Fixed
Related Reports
Blocks :  
Description
public class Main {
    interface F {void f();}

    public static void main(String[] args) {
        class Local {
            public Local() {
                F f = () -> new Local();
            }
        }
    }
}

javac Main.java


The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
        at com.sun.tools.javac.tree.TreeInfo.name(TreeInfo.java:740)
        at com.sun.tools.javac.comp.Lower$BasicFreeVarCollector.visitApply(Lower.java:250)
        at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1459)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.visitExec(TreeScanner.java:175)
        at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1290)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitBlock(TreeScanner.java:105)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:903)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.visitMethodDef(TreeScanner.java:91)
        at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:772)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitClassDef(TreeScanner.java:80)
        at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:687)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.comp.LambdaToMethod$LambdaAnalyzerPreprocessor.captureLocalClassDefs(LambdaToMethod.java:1327)
        at com.sun.tools.javac.comp.LambdaToMethod$LambdaAnalyzerPreprocessor$1.addFreeVars(LambdaToMethod.java:1308)
        at com.sun.tools.javac.comp.Lower$BasicFreeVarCollector.visitNewClass(Lower.java:242)
        at com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1510)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.visitLambda(TreeScanner.java:221)
        at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1618)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.visitVarDef(TreeScanner.java:98)
        at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:846)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitBlock(TreeScanner.java:105)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:903)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.visitMethodDef(TreeScanner.java:91)
        at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:772)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitClassDef(TreeScanner.java:80)
        at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:687)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.comp.LambdaToMethod$LambdaAnalyzerPreprocessor.captureLocalClassDefs(LambdaToMethod.java:1327)
        at com.sun.tools.javac.comp.LambdaToMethod$LambdaAnalyzerPreprocessor$1.addFreeVars(LambdaToMethod.java:1308)
        at com.sun.tools.javac.comp.Lower$BasicFreeVarCollector.visitNewClass(Lower.java:242) ...

bitter_fox writes:

It may be a cause that c.s.t.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor#capturelocalClassDefs is called recursively.

            void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
                JCClassDecl localCDef = localClassDefs.get(csym);
                if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
                    BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
                        @Override
                        void addFreeVars(ClassSymbol c) {
                            captureLocalClassDefs(c, lambdaContext);
                        }
            // ...
                    };
                    fvc.scan(localCDef);
                }
        }


Comments
Verified
29-07-2014

Release team: Approved for deferral.
11-12-2013

8-defer-request : Although I have a fix for this problem (attached), fixing it would expose a new bug (JDK-8029852) wherein the compiler generates bad code that raises a verification error at class load time. This bad code will be generated in cases where a local variable is referenced within the local class, a very common, probably usual occurrence. While both would be important to fix, their combined complexity and fragility seems inappropriate for the small remaining time window.
10-12-2013

Attached is a patch that fixes the problem (including tests).
10-12-2013