8215470: Bad EnclosingMethod attribute on classes declared in lambdas
Reviewed-by: mcimadamore
--- 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 {