6996914: Diamond inference: problem when accessing protected constructor
Summary: special resolution scheme for diamond inference needs to open up protected constructors in anon inner class creation
Reviewed-by: jjg
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Tue Nov 09 17:49:24 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Nov 10 12:37:25 2010 +0000
@@ -1552,7 +1552,7 @@
// Attribute clazz expression and store
// symbol + type back into the attributed tree.
Type clazztype = attribType(clazz, env);
- Pair<Scope,Scope> mapping = getSyntheticScopeMapping(clazztype);
+ Pair<Scope,Scope> mapping = getSyntheticScopeMapping(clazztype, cdef != null);
if (!TreeInfo.isDiamond(tree)) {
clazztype = chk.checkClassType(
tree.clazz.pos(), clazztype, true);
@@ -1849,7 +1849,7 @@
* inference. The inferred return type of the synthetic constructor IS
* the inferred type for the diamond operator.
*/
- private Pair<Scope, Scope> getSyntheticScopeMapping(Type ctype) {
+ private Pair<Scope, Scope> getSyntheticScopeMapping(Type ctype, boolean overrideProtectedAccess) {
if (ctype.tag != CLASS) {
return erroneousMapping;
}
@@ -1860,6 +1860,12 @@
e.scope != null;
e = e.next()) {
MethodSymbol newConstr = (MethodSymbol) e.sym.clone(ctype.tsym);
+ if (overrideProtectedAccess && (newConstr.flags() & PROTECTED) != 0) {
+ //make protected constructor public (this is required for
+ //anonymous inner class creation expressions using diamond)
+ newConstr.flags_field |= PUBLIC;
+ newConstr.flags_field &= ~PROTECTED;
+ }
newConstr.name = names.init;
List<Type> oldTypeargs = List.nil();
if (newConstr.type.tag == FORALL) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/6996914/T6996914a.java Wed Nov 10 12:37:25 2010 +0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2010, 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 6996914
+ * @summary Diamond inference: problem when accessing protected constructor
+ * @run main T6996914a
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class T6996914a {
+
+ enum PackageKind {
+ DEFAULT("", ""),
+ A("package a;", "import a.*;");
+
+ String pkgDecl;
+ String importDecl;
+
+ PackageKind(String pkgDecl, String importDecl) {
+ this.pkgDecl = pkgDecl;
+ this.importDecl = importDecl;
+ }
+ }
+
+ enum DiamondKind {
+ STANDARD("new Foo<>();"),
+ ANON("new Foo<>() {};");
+
+ String expr;
+
+ DiamondKind(String expr) {
+ this.expr = expr;
+ }
+ }
+
+ enum ConstructorKind {
+ PACKAGE(""),
+ PROTECTED("protected"),
+ PRIVATE("private"),
+ PUBLIC("public");
+
+ String mod;
+
+ ConstructorKind(String mod) {
+ this.mod = mod;
+ }
+ }
+
+ static class FooClass extends SimpleJavaFileObject {
+
+ final static String sourceStub =
+ "#P\n" +
+ "public class Foo<X> {\n" +
+ " #M Foo() {}\n" +
+ "}\n";
+
+ String source;
+
+ public FooClass(PackageKind pk, ConstructorKind ck) {
+ super(URI.create("myfo:/" + (pk != PackageKind.DEFAULT ? "a/Foo.java" : "Foo.java")),
+ JavaFileObject.Kind.SOURCE);
+ source = sourceStub.replace("#P", pk.pkgDecl).replace("#M", ck.mod);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ static class ClientClass extends SimpleJavaFileObject {
+
+ final static String sourceStub =
+ "#I\n" +
+ "class Test {\n" +
+ " Foo<String> fs = #D\n" +
+ "}\n";
+
+ String source;
+
+ public ClientClass(PackageKind pk, DiamondKind dk) {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ source = sourceStub.replace("#I", pk.importDecl).replace("#D", dk.expr);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ for (PackageKind pk : PackageKind.values()) {
+ for (ConstructorKind ck : ConstructorKind.values()) {
+ for (DiamondKind dk : DiamondKind.values()) {
+ compileAndCheck(pk, ck, dk);
+ }
+ }
+ }
+ }
+
+ static void compileAndCheck(PackageKind pk, ConstructorKind ck, DiamondKind dk) throws Exception {
+ FooClass foo = new FooClass(pk, ck);
+ ClientClass client = new ClientClass(pk, dk);
+ final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+ ErrorListener el = new ErrorListener();
+ JavacTask ct = (JavacTask)tool.getTask(null, null, el,
+ null, null, Arrays.asList(foo, client));
+ ct.analyze();
+ if (el.errors > 0 == check(pk, ck, dk)) {
+ String msg = el.errors > 0 ?
+ "Error compiling files" :
+ "No error when compiling files";
+ throw new AssertionError(msg + ": \n" + foo.source + "\n" + client.source);
+ }
+ }
+
+ static boolean check(PackageKind pk, ConstructorKind ck, DiamondKind dk) {
+ switch (pk) {
+ case A: return ck == ConstructorKind.PUBLIC ||
+ (ck == ConstructorKind.PROTECTED && dk == DiamondKind.ANON);
+ case DEFAULT: return ck != ConstructorKind.PRIVATE;
+ default: throw new AssertionError("Unknown package kind");
+ }
+ }
+
+ /**
+ * DiagnosticListener to count any errors that occur
+ */
+ private static class ErrorListener implements DiagnosticListener<JavaFileObject> {
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ switch (diagnostic.getKind()) {
+ case ERROR:
+ errors++;
+ }
+ }
+ int errors;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/6996914/T6996914b.java Wed Nov 10 12:37:25 2010 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 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 6996914
+ * @summary Diamond inference: problem when accessing protected constructor
+ * @compile T6996914b.java
+ */
+
+class Super<X,Y> {
+ private Super(Integer i, Y y, X x) {}
+ public Super(Number n, X x, Y y) {}
+}
+
+class Test {
+ Super<String,Integer> ssi1 = new Super<>(1, "", 2);
+ Super<String,Integer> ssi2 = new Super<>(1, "", 2) {};
+}