changeset 1829:dae2aede7f35

8008227: Mixing lambdas with anonymous classes leads to NPE thrown by compiler
author mcimadamore
date Thu, 14 Feb 2013 17:28:59 +0000
parents 89bc9300b5e5
children 5868b9c53cfd
files src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java test/tools/javac/lambda/LambdaConv27.java
diffstat 2 files changed, 76 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Feb 14 12:16:32 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Feb 14 17:28:59 2013 +0000
@@ -1055,7 +1055,7 @@
         }
 
         @Override
-        public void visitClassDef(JCClassDecl tree) {
+        public void visitClassDef(final JCClassDecl tree) {
             List<Frame> prevStack = frameStack;
             Map<String, Integer> prevSerializableLambdaCount =
                     serializableLambdaCounts;
@@ -1066,19 +1066,25 @@
                 if (directlyEnclosingLambda() != null) {
                     tree.sym.owner = owner();
                     LambdaTranslationContext lambdaContext = (LambdaTranslationContext)contextMap.get(directlyEnclosingLambda());
-                    Type encl = lambdaContext.enclosingType();
-                    if (encl.hasTag(NONE)) {
-                        //if the translated lambda body occurs in a static context,
-                        //any class declaration within it must be made static
-                        //@@@TODO: What about nested classes within lambda?
-                        tree.sym.flags_field |= STATIC;
-                        ((ClassType)tree.sym.type).setEnclosingType(Type.noType);
-                    } else {
-                        //if the translated lambda body is in an instance context
-                        //the enclosing type of any class declaration within it
-                        //must be updated to point to the new enclosing type (if any)
-                        ((ClassType)tree.sym.type).setEnclosingType(encl);
-                    }
+                    lambdaContext.listeners =
+                            lambdaContext.listeners.prepend(new LambdaTranslationContextListener() {
+                        @Override
+                        void onComplete(LambdaTranslationContext context) {
+                            Type encl = context.enclosingType();
+                            if (encl.hasTag(NONE)) {
+                                //if the translated lambda body occurs in a static context,
+                                //any class declaration within it must be made static
+                                //@@@TODO: What about nested classes within lambda?
+                                tree.sym.flags_field |= STATIC;
+                                ((ClassType)tree.sym.type).setEnclosingType(Type.noType);
+                            } else {
+                                //if the translated lambda body is in an instance context
+                                //the enclosing type of any class declaration within it
+                                //must be updated to point to the new enclosing type (if any)
+                                ((ClassType)tree.sym.type).setEnclosingType(encl);
+                            }
+                        }
+                    });
                 }
                 frameStack = frameStack.prepend(new Frame(tree));
                 super.visitClassDef(tree);
@@ -1462,6 +1468,13 @@
                 locals = locals.prepend(sym);
             }
         }
+        
+        /**
+         * Listener class used to keep track of lambda translation context changes
+         */
+        abstract class LambdaTranslationContextListener {
+            abstract void onComplete(LambdaTranslationContext context);
+        }
 
         /**
          * This class is used to store important information regarding translation of
@@ -1535,6 +1548,8 @@
             Symbol translatedSym;
 
             List<JCVariableDecl> syntheticParams;
+            
+            List<LambdaTranslationContextListener> listeners;
 
             LambdaTranslationContext(JCLambda tree) {
                 super(tree);
@@ -1544,6 +1559,7 @@
                 }
                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
+                this.listeners = List.nil();
             }
 
             /**
@@ -1654,10 +1670,15 @@
                 translatedSym.type = types.createMethodTypeWithParameters(
                         generatedLambdaSig(),
                         TreeInfo.types(syntheticParams));
+                
+                //notify listeners
+                for (LambdaTranslationContextListener listener : listeners) {
+                    listener.onComplete(this);
+                }
             }
 
             Type enclosingType() {
-                return owner.isStatic() ?
+                return translatedSym.isStatic() ?
                         Type.noType :
                         owner.enclClass().type;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv27.java	Thu Feb 14 17:28:59 2013 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8008227
+ * @summary Mixing lambdas with anonymous classes leads to NPE thrown by compiler
+ * @run main LambdaConv27
+ */
+public class LambdaConv27 {
+
+     public static void main(String[] args) {
+         SAM s = ()-> { SAM s2 = ()->{ new Object() { }; }; s2.m(); };
+         s.m();
+     }
+
+     interface SAM {
+         void m();
+     }
+}