8215470: Bad EnclosingMethod attribute on classes declared in lambdas
authorvromero
Tue, 14 May 2019 11:28:44 -0400
changeset 54846 e4049522b074
parent 54845 63ba0b902181
child 54847 59ea39bb2809
8215470: Bad EnclosingMethod attribute on classes declared in lambdas Reviewed-by: mcimadamore
src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
test/langtools/tools/javac/T8215470/BadEnclosingMethodAttrTest.java
test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java
test/langtools/tools/javac/lambda/LambdaInnerTypeVarReflect.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Sun Apr 07 09:13:17 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue May 14 11:28:44 2019 -0400
@@ -1963,6 +1963,13 @@
             return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
         }
 
+        /** override this method to point to the original enclosing method if this method symbol represents a synthetic
+         *  lambda method
+         */
+        public MethodSymbol originalEnclosingMethod() {
+            return this;
+        }
+
         /** The implementation of this (abstract) symbol in class origin;
          *  null if none exists. Synthetic methods are not considered
          *  as possible implementations.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Sun Apr 07 09:13:17 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue May 14 11:28:44 2019 -0400
@@ -603,21 +603,6 @@
             tree.init = translate(tree.init);
             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
             result = tree;
-        } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
-            JCExpression init = translate(tree.init);
-            VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
-            int prevPos = make.pos;
-            try {
-                result = make.at(tree).VarDef(xsym, init);
-            } finally {
-                make.at(prevPos);
-            }
-            // Replace the entered symbol for this variable
-            WriteableScope sc = tree.sym.owner.members();
-            if (sc != null) {
-                sc.remove(tree.sym);
-                sc.enter(xsym);
-            }
         } else {
             super.visitVarDef(tree);
         }
@@ -1572,9 +1557,6 @@
                 // Check for type variables (including as type arguments).
                 // If they occur within class nested in a lambda, mark for erasure
                 Type type = tree.sym.asType();
-                if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
-                    ltc.addSymbol(tree.sym, TYPE_VAR);
-                }
             }
 
             List<Frame> prevStack = frameStack;
@@ -1944,8 +1926,17 @@
                  }
 
                 // This symbol will be filled-in in complete
-                this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
-
+                if (owner.kind == MTH) {
+                    final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
+                    this.translatedSym = new MethodSymbol(SYNTHETIC | PRIVATE, null, null, owner.enclClass()) {
+                        @Override
+                        public MethodSymbol originalEnclosingMethod() {
+                            return originalOwner;
+                        }
+                    };
+                } else {
+                    this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
+                }
                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
 
                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
@@ -1953,7 +1944,6 @@
                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
-                translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
 
                 freeVarProcessedLocalClasses = new HashSet<>();
             }
@@ -2046,16 +2036,6 @@
                     case CAPTURED_THIS:
                         ret = sym;  // self represented
                         break;
-                    case TYPE_VAR:
-                        // Just erase the type var
-                        ret = new VarSymbol(sym.flags(), sym.name,
-                                types.erasure(sym.type), sym.owner);
-
-                        /* this information should also be kept for LVT generation at Gen
-                         * a Symbol with pos < startPos won't be tracked.
-                         */
-                        ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
-                        break;
                     case CAPTURED_VAR:
                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
                             @Override
@@ -2352,8 +2332,7 @@
         LOCAL_VAR,      // original to translated lambda locals
         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
-        CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
-        TYPE_VAR;      // original to translated lambda type variables
+        CAPTURED_OUTER_THIS; // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
 
         boolean propagateAnnotations() {
             switch (this) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sun Apr 07 09:13:17 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue May 14 11:28:44 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -323,9 +323,9 @@
             (c.owner.type == null // local to init block
              || c.owner.kind != MTH) // or member init
             ? null
-            : (MethodSymbol)c.owner;
+            : ((MethodSymbol)c.owner).originalEnclosingMethod();
         databuf.appendChar(poolWriter.putClass(enclClass));
-        databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
+        databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod));
         endAttr(alenIdx);
         return 1;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8215470/BadEnclosingMethodAttrTest.java	Tue May 14 11:28:44 2019 -0400
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019, 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 8215470
+ * @summary Bad EnclosingMethod attribute on classes declared in lambdas
+ * @modules jdk.compiler/com.sun.tools.javac.util
+ */
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import com.sun.tools.javac.util.Assert;
+
+public class BadEnclosingMethodAttrTest<T> {
+    protected BadEnclosingMethodAttrTest() {
+        Assert.check(getClass().getEnclosingMethod().toString().equals("static void BadEnclosingMethodAttrTest.lambdaScope(java.lang.Object)"));
+        Type typeFromEnclosingMethod = getClass().getEnclosingMethod().getGenericParameterTypes()[0];
+        ParameterizedType paramType = (ParameterizedType) getClass().getGenericSuperclass();
+        Type typeFromGenericClass = paramType.getActualTypeArguments()[0];
+        Assert.check(typeFromEnclosingMethod.equals(typeFromGenericClass));
+    }
+
+    static <X> void lambdaScope(X x) {
+        Runnable r = () -> {
+            new BadEnclosingMethodAttrTest<X>() {};
+        };
+        r.run();
+    }
+
+    public static void main(final String[] args) {
+        lambdaScope("");
+    }
+}
--- a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java	Sun Apr 07 09:13:17 2019 +0200
+++ b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java	Tue May 14 11:28:44 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8042931
+ * @bug 8042931 8215470
  * @summary Checking EnclosingMethod attribute of anonymous/local class.
  * @library /tools/lib /tools/javac/lib ../lib
  * @modules jdk.compiler/com.sun.tools.javac.api
@@ -245,7 +245,7 @@
         // anonymous and local classes in lambda
         @ExpectedEnclosingMethod(
                 info = "EnclosingLambda in EnclosingMethodTest",
-                enclosingMethod = "lambda",
+                enclosingMethod = "<init>",
                 enclosingClazz = EnclosingMethodTest.class
         )
         class EnclosingLambda {
@@ -325,7 +325,7 @@
             // anonymous and local classes in lambda
             @ExpectedEnclosingMethod(
                     info = "EnclosingLambda in notEnclosing01",
-                    enclosingMethod = "lambda",
+                    enclosingMethod = "<init>",
                     enclosingClazz = notEnclosing01.class
             )
             class EnclosingLambda {
@@ -382,7 +382,7 @@
             // anonymous and local classes in lambda
             @ExpectedEnclosingMethod(
                     info = "EnclosingLambda in notEnclosing02",
-                    enclosingMethod = "lambda",
+                    enclosingMethod = "<clinit>",
                     enclosingClazz = notEnclosing02.class
             )
             class EnclosingLambda {
@@ -460,7 +460,7 @@
             // anonymous and local classes in lambda
             @ExpectedEnclosingMethod(
                     info = "EnclosingLambda in notEnclosing03",
-                    enclosingMethod = "lambda",
+                    enclosingMethod = "<init>",
                     enclosingClazz = notEnclosing03.class
             )
             class EnclosingLambda {
@@ -517,7 +517,7 @@
             // anonymous and local classes in lambda
             @ExpectedEnclosingMethod(
                     info = "EnclosingLambda in notEnclosing04",
-                    enclosingMethod = "lambda",
+                    enclosingMethod = "<clinit>",
                     enclosingClazz = notEnclosing04.class
             )
             class EnclosingLambda {
--- a/test/langtools/tools/javac/lambda/LambdaInnerTypeVarReflect.java	Sun Apr 07 09:13:17 2019 +0200
+++ b/test/langtools/tools/javac/lambda/LambdaInnerTypeVarReflect.java	Tue May 14 11:28:44 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -77,7 +77,7 @@
 
         String javapOut = sw.toString();
         assertTrue(javapOut.contains(innerName));
-        assertTrue(!javapOut.contains("RRRRR"));
+        assertTrue(javapOut.contains("RRRRR"));
     }
 
     public static void main(String[] args) throws IOException {