Wed, 27 Jul 2011 19:01:08 +0100
7046778: Project Coin: problem with diamond and member inner classes
Summary: Diamond inference generates spurious error messages when target type is a member inner class
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 27 19:00:53 2011 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 27 19:01:08 2011 +0100 1.3 @@ -1837,7 +1837,7 @@ 1.4 try { 1.5 constructor = rs.resolveDiamond(tree.pos(), 1.6 localEnv, 1.7 - clazztype.tsym.type, 1.8 + clazztype, 1.9 argtypes, 1.10 typeargtypes); 1.11 } finally { 1.12 @@ -2872,8 +2872,10 @@ 1.13 1.14 if (clazztype.tag == CLASS) { 1.15 List<Type> formals = clazztype.tsym.type.getTypeArguments(); 1.16 - 1.17 - if (actuals.length() == formals.length() || actuals.length() == 0) { 1.18 + if (actuals.isEmpty()) //diamond 1.19 + actuals = formals; 1.20 + 1.21 + if (actuals.length() == formals.length()) { 1.22 List<Type> a = actuals; 1.23 List<Type> f = formals; 1.24 while (a.nonEmpty()) {
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/generics/diamond/7046778/DiamondAndInnerClassTest.java Wed Jul 27 19:01:08 2011 +0100 2.3 @@ -0,0 +1,336 @@ 2.4 +/* 2.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test 2.29 + * @bug 7046778 2.30 + * @summary Project Coin: problem with diamond and member inner classes 2.31 + */ 2.32 + 2.33 +import com.sun.source.util.JavacTask; 2.34 +import java.net.URI; 2.35 +import java.util.Arrays; 2.36 +import javax.tools.Diagnostic; 2.37 +import javax.tools.JavaCompiler; 2.38 +import javax.tools.JavaFileObject; 2.39 +import javax.tools.SimpleJavaFileObject; 2.40 +import javax.tools.StandardJavaFileManager; 2.41 +import javax.tools.ToolProvider; 2.42 + 2.43 +public class DiamondAndInnerClassTest { 2.44 + 2.45 + static int checkCount = 0; 2.46 + 2.47 + enum TypeArgumentKind { 2.48 + NONE(""), 2.49 + STRING("<String>"), 2.50 + INTEGER("<Integer>"), 2.51 + DIAMOND("<>"); 2.52 + 2.53 + String typeargStr; 2.54 + 2.55 + private TypeArgumentKind(String typeargStr) { 2.56 + this.typeargStr = typeargStr; 2.57 + } 2.58 + 2.59 + boolean compatible(TypeArgumentKind that) { 2.60 + switch (this) { 2.61 + case NONE: return true; 2.62 + case STRING: return that != INTEGER; 2.63 + case INTEGER: return that != STRING; 2.64 + default: throw new AssertionError("Unexpected decl kind: " + this); 2.65 + } 2.66 + } 2.67 + 2.68 + boolean compatible(ArgumentKind that) { 2.69 + switch (this) { 2.70 + case NONE: return true; 2.71 + case STRING: return that == ArgumentKind.STRING; 2.72 + case INTEGER: return that == ArgumentKind.INTEGER; 2.73 + default: throw new AssertionError("Unexpected decl kind: " + this); 2.74 + } 2.75 + } 2.76 + } 2.77 + 2.78 + enum ArgumentKind { 2.79 + OBJECT("(Object)null"), 2.80 + STRING("(String)null"), 2.81 + INTEGER("(Integer)null"); 2.82 + 2.83 + String argStr; 2.84 + 2.85 + private ArgumentKind(String argStr) { 2.86 + this.argStr = argStr; 2.87 + } 2.88 + } 2.89 + 2.90 + enum TypeQualifierArity { 2.91 + ONE(1, "A1#TA1"), 2.92 + TWO(2, "A1#TA1.A2#TA2"), 2.93 + THREE(3, "A1#TA1.A2#TA2.A3#TA3"); 2.94 + 2.95 + int n; 2.96 + String qualifierStr; 2.97 + 2.98 + private TypeQualifierArity(int n, String qualifierStr) { 2.99 + this.n = n; 2.100 + this.qualifierStr = qualifierStr; 2.101 + } 2.102 + 2.103 + String getType(TypeArgumentKind... typeArgumentKinds) { 2.104 + String res = qualifierStr; 2.105 + for (int i = 1 ; i <= typeArgumentKinds.length ; i++) { 2.106 + res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr); 2.107 + } 2.108 + return res; 2.109 + } 2.110 + 2.111 + boolean matches(InnerClassDeclArity innerClassDeclArity) { 2.112 + return n ==innerClassDeclArity.n; 2.113 + } 2.114 + } 2.115 + 2.116 + enum InnerClassDeclArity { 2.117 + ONE(1, "class A1<X> { A1(X x1) { } #B }"), 2.118 + TWO(2, "class A1<X1> { class A2<X2> { A2(X1 x1, X2 x2) { } #B } }"), 2.119 + THREE(3, "class A1<X1> { class A2<X2> { class A3<X3> { A3(X1 x1, X2 x2, X3 x3) { } #B } } }"); 2.120 + 2.121 + int n; 2.122 + String classDeclStr; 2.123 + 2.124 + private InnerClassDeclArity(int n, String classDeclStr) { 2.125 + this.n = n; 2.126 + this.classDeclStr = classDeclStr; 2.127 + } 2.128 + } 2.129 + 2.130 + enum ArgumentListArity { 2.131 + ONE(1, "(#A1)"), 2.132 + TWO(2, "(#A1,#A2)"), 2.133 + THREE(3, "(#A1,#A2,#A3)"); 2.134 + 2.135 + int n; 2.136 + String argListStr; 2.137 + 2.138 + private ArgumentListArity(int n, String argListStr) { 2.139 + this.n = n; 2.140 + this.argListStr = argListStr; 2.141 + } 2.142 + 2.143 + String getArgs(ArgumentKind... argumentKinds) { 2.144 + String res = argListStr; 2.145 + for (int i = 1 ; i <= argumentKinds.length ; i++) { 2.146 + res = res.replace("#A" + i, argumentKinds[i-1].argStr); 2.147 + } 2.148 + return res; 2.149 + } 2.150 + 2.151 + boolean matches(InnerClassDeclArity innerClassDeclArity) { 2.152 + return n ==innerClassDeclArity.n; 2.153 + } 2.154 + } 2.155 + 2.156 + public static void main(String... args) throws Exception { 2.157 + 2.158 + //create default shared JavaCompiler - reused across multiple compilations 2.159 + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 2.160 + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); 2.161 + 2.162 + for (InnerClassDeclArity innerClassDeclArity : InnerClassDeclArity.values()) { 2.163 + for (TypeQualifierArity declType : TypeQualifierArity.values()) { 2.164 + if (!declType.matches(innerClassDeclArity)) continue; 2.165 + for (TypeQualifierArity newClassType : TypeQualifierArity.values()) { 2.166 + if (!newClassType.matches(innerClassDeclArity)) continue; 2.167 + for (ArgumentListArity argList : ArgumentListArity.values()) { 2.168 + if (!argList.matches(innerClassDeclArity)) continue; 2.169 + for (TypeArgumentKind taDecl1 : TypeArgumentKind.values()) { 2.170 + boolean isDeclRaw = taDecl1 == TypeArgumentKind.NONE; 2.171 + //no diamond on decl site 2.172 + if (taDecl1 == TypeArgumentKind.DIAMOND) continue; 2.173 + for (TypeArgumentKind taSite1 : TypeArgumentKind.values()) { 2.174 + boolean isSiteRaw = taSite1 == TypeArgumentKind.NONE; 2.175 + //diamond only allowed on the last type qualifier 2.176 + if (taSite1 == TypeArgumentKind.DIAMOND && 2.177 + innerClassDeclArity != InnerClassDeclArity.ONE) continue; 2.178 + for (ArgumentKind arg1 : ArgumentKind.values()) { 2.179 + if (innerClassDeclArity == innerClassDeclArity.ONE) { 2.180 + new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, 2.181 + argList, new TypeArgumentKind[] {taDecl1}, 2.182 + new TypeArgumentKind[] {taSite1}, new ArgumentKind[] {arg1}).run(comp, fm); 2.183 + continue; 2.184 + } 2.185 + for (TypeArgumentKind taDecl2 : TypeArgumentKind.values()) { 2.186 + //no rare types 2.187 + if (isDeclRaw != (taDecl2 == TypeArgumentKind.NONE)) continue; 2.188 + //no diamond on decl site 2.189 + if (taDecl2 == TypeArgumentKind.DIAMOND) continue; 2.190 + for (TypeArgumentKind taSite2 : TypeArgumentKind.values()) { 2.191 + //no rare types 2.192 + if (isSiteRaw != (taSite2 == TypeArgumentKind.NONE)) continue; 2.193 + //diamond only allowed on the last type qualifier 2.194 + if (taSite2 == TypeArgumentKind.DIAMOND && 2.195 + innerClassDeclArity != InnerClassDeclArity.TWO) continue; 2.196 + for (ArgumentKind arg2 : ArgumentKind.values()) { 2.197 + if (innerClassDeclArity == innerClassDeclArity.TWO) { 2.198 + new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, 2.199 + argList, new TypeArgumentKind[] {taDecl1, taDecl2}, 2.200 + new TypeArgumentKind[] {taSite1, taSite2}, 2.201 + new ArgumentKind[] {arg1, arg2}).run(comp, fm); 2.202 + continue; 2.203 + } 2.204 + for (TypeArgumentKind taDecl3 : TypeArgumentKind.values()) { 2.205 + //no rare types 2.206 + if (isDeclRaw != (taDecl3 == TypeArgumentKind.NONE)) continue; 2.207 + //no diamond on decl site 2.208 + if (taDecl3 == TypeArgumentKind.DIAMOND) continue; 2.209 + for (TypeArgumentKind taSite3 : TypeArgumentKind.values()) { 2.210 + //no rare types 2.211 + if (isSiteRaw != (taSite3 == TypeArgumentKind.NONE)) continue; 2.212 + //diamond only allowed on the last type qualifier 2.213 + if (taSite3 == TypeArgumentKind.DIAMOND && 2.214 + innerClassDeclArity != InnerClassDeclArity.THREE) continue; 2.215 + for (ArgumentKind arg3 : ArgumentKind.values()) { 2.216 + if (innerClassDeclArity == innerClassDeclArity.THREE) { 2.217 + new DiamondAndInnerClassTest(innerClassDeclArity, declType, newClassType, 2.218 + argList, new TypeArgumentKind[] {taDecl1, taDecl2, taDecl3}, 2.219 + new TypeArgumentKind[] {taSite1, taSite2, taSite3}, 2.220 + new ArgumentKind[] {arg1, arg2, arg3}).run(comp, fm); 2.221 + continue; 2.222 + } 2.223 + } 2.224 + } 2.225 + } 2.226 + } 2.227 + } 2.228 + } 2.229 + } 2.230 + } 2.231 + } 2.232 + } 2.233 + } 2.234 + } 2.235 + } 2.236 + System.out.println("Total check executed: " + checkCount); 2.237 + } 2.238 + 2.239 + InnerClassDeclArity innerClassDeclArity; 2.240 + TypeQualifierArity declType; 2.241 + TypeQualifierArity siteType; 2.242 + ArgumentListArity argList; 2.243 + TypeArgumentKind[] declTypeArgumentKinds; 2.244 + TypeArgumentKind[] siteTypeArgumentKinds; 2.245 + ArgumentKind[] argumentKinds; 2.246 + JavaSource source; 2.247 + DiagnosticChecker diagChecker; 2.248 + 2.249 + DiamondAndInnerClassTest(InnerClassDeclArity innerClassDeclArity, 2.250 + TypeQualifierArity declType, TypeQualifierArity siteType, ArgumentListArity argList, 2.251 + TypeArgumentKind[] declTypeArgumentKinds, TypeArgumentKind[] siteTypeArgumentKinds, 2.252 + ArgumentKind[] argumentKinds) { 2.253 + this.innerClassDeclArity = innerClassDeclArity; 2.254 + this.declType = declType; 2.255 + this.siteType = siteType; 2.256 + this.argList = argList; 2.257 + this.declTypeArgumentKinds = declTypeArgumentKinds; 2.258 + this.siteTypeArgumentKinds = siteTypeArgumentKinds; 2.259 + this.argumentKinds = argumentKinds; 2.260 + this.source = new JavaSource(); 2.261 + this.diagChecker = new DiagnosticChecker(); 2.262 + } 2.263 + 2.264 + class JavaSource extends SimpleJavaFileObject { 2.265 + 2.266 + String bodyTemplate = "#D res = new #S#AL;"; 2.267 + 2.268 + String source; 2.269 + 2.270 + public JavaSource() { 2.271 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 2.272 + source = innerClassDeclArity.classDeclStr.replace("#B", bodyTemplate) 2.273 + .replace("#D", declType.getType(declTypeArgumentKinds)) 2.274 + .replace("#S", siteType.getType(siteTypeArgumentKinds)) 2.275 + .replace("#AL", argList.getArgs(argumentKinds)); 2.276 + } 2.277 + 2.278 + @Override 2.279 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 2.280 + return source; 2.281 + } 2.282 + } 2.283 + 2.284 + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { 2.285 + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, 2.286 + null, null, Arrays.asList(source)); 2.287 + try { 2.288 + ct.analyze(); 2.289 + } catch (Throwable ex) { 2.290 + throw new AssertionError("Error thron when compiling the following code:\n" + source.getCharContent(true)); 2.291 + } 2.292 + check(); 2.293 + } 2.294 + 2.295 + void check() { 2.296 + checkCount++; 2.297 + 2.298 + boolean errorExpected = false; 2.299 + 2.300 + TypeArgumentKind[] expectedArgKinds = new TypeArgumentKind[innerClassDeclArity.n]; 2.301 + 2.302 + for (int i = 0 ; i < innerClassDeclArity.n ; i++) { 2.303 + if (!declTypeArgumentKinds[i].compatible(siteTypeArgumentKinds[i])) { 2.304 + errorExpected = true; 2.305 + break; 2.306 + } 2.307 + expectedArgKinds[i] = siteTypeArgumentKinds[i] == TypeArgumentKind.DIAMOND ? 2.308 + declTypeArgumentKinds[i] : siteTypeArgumentKinds[i]; 2.309 + } 2.310 + 2.311 + if (!errorExpected) { 2.312 + for (int i = 0 ; i < innerClassDeclArity.n ; i++) { 2.313 + //System.out.println("check " + expectedArgKinds[i] + " against " + argumentKinds[i]); 2.314 + if (!expectedArgKinds[i].compatible(argumentKinds[i])) { 2.315 + errorExpected = true; 2.316 + break; 2.317 + } 2.318 + } 2.319 + } 2.320 + 2.321 + if (errorExpected != diagChecker.errorFound) { 2.322 + throw new Error("invalid diagnostics for source:\n" + 2.323 + source.getCharContent(true) + 2.324 + "\nFound error: " + diagChecker.errorFound + 2.325 + "\nExpected error: " + errorExpected); 2.326 + } 2.327 + } 2.328 + 2.329 + static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 2.330 + 2.331 + boolean errorFound; 2.332 + 2.333 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 2.334 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 2.335 + errorFound = true; 2.336 + } 2.337 + } 2.338 + } 2.339 +}
3.1 --- a/test/tools/javac/generics/diamond/neg/Neg09.out Wed Jul 27 19:00:53 2011 +0100 3.2 +++ b/test/tools/javac/generics/diamond/neg/Neg09.out Wed Jul 27 19:01:08 2011 +0100 3.3 @@ -1,5 +1,5 @@ 3.4 -Neg09.java:17:34: compiler.err.cant.apply.diamond.1: Neg09.Member, (compiler.misc.diamond.and.anon.class: Neg09.Member) 3.5 -Neg09.java:18:34: compiler.err.cant.apply.diamond.1: Neg09.Nested, (compiler.misc.diamond.and.anon.class: Neg09.Nested) 3.6 -Neg09.java:22:39: compiler.err.cant.apply.diamond.1: Neg09.Member, (compiler.misc.diamond.and.anon.class: Neg09.Member) 3.7 -Neg09.java:23:40: compiler.err.cant.apply.diamond.1: Neg09.Nested, (compiler.misc.diamond.and.anon.class: Neg09.Nested) 3.8 +Neg09.java:17:34: compiler.err.cant.apply.diamond.1: Neg09.Member<X>, (compiler.misc.diamond.and.anon.class: Neg09.Member<X>) 3.9 +Neg09.java:18:34: compiler.err.cant.apply.diamond.1: Neg09.Nested<X>, (compiler.misc.diamond.and.anon.class: Neg09.Nested<X>) 3.10 +Neg09.java:22:39: compiler.err.cant.apply.diamond.1: Neg09.Member<X>, (compiler.misc.diamond.and.anon.class: Neg09.Member<X>) 3.11 +Neg09.java:23:40: compiler.err.cant.apply.diamond.1: Neg09.Nested<X>, (compiler.misc.diamond.and.anon.class: Neg09.Nested<X>) 3.12 4 errors