GenericOverrideTest.java revision 3019:176472b94f2e
1/* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 7062745 8006694 8129962 27 * @summary Regression: difference in overload resolution when two methods 28 * are maximally specific 29 * temporarily workaround combo tests are causing time out in several platforms 30 * @library /tools/javac/lib 31 * @modules jdk.compiler/com.sun.tools.javac.api 32 * jdk.compiler/com.sun.tools.javac.code 33 * jdk.compiler/com.sun.tools.javac.comp 34 * jdk.compiler/com.sun.tools.javac.main 35 * jdk.compiler/com.sun.tools.javac.tree 36 * jdk.compiler/com.sun.tools.javac.util 37 * @build combo.ComboTestHelper 38 * @run main GenericOverrideTest 39 */ 40 41import java.io.IOException; 42 43import combo.ComboInstance; 44import combo.ComboParameter; 45import combo.ComboTask.Result; 46import combo.ComboTestHelper; 47 48public class GenericOverrideTest extends ComboInstance<GenericOverrideTest> { 49 50 enum SourceLevel { 51 SOURCE_7("-source", "7"), 52 SOURCE_DEFAULT(); 53 54 String[] opts; 55 56 SourceLevel(String... opts) { 57 this.opts = opts; 58 } 59 } 60 61 enum SignatureKind implements ComboParameter { 62 NON_GENERIC(""), 63 GENERIC("<X>"); 64 65 String paramStr; 66 67 SignatureKind(String paramStr) { 68 this.paramStr = paramStr; 69 } 70 71 @Override 72 public String expand(String optParameter) { 73 return paramStr; 74 } 75 } 76 77 enum ReturnTypeKind implements ComboParameter { 78 LIST("List"), 79 ARRAYLIST("ArrayList"); 80 81 String retStr; 82 83 ReturnTypeKind(String retStr) { 84 this.retStr = retStr; 85 } 86 87 boolean moreSpecificThan(ReturnTypeKind that) { 88 switch (this) { 89 case LIST: 90 return that == this; 91 case ARRAYLIST: 92 return that == LIST || that == ARRAYLIST; 93 default: throw new AssertionError("Unexpected ret kind: " + this); 94 } 95 } 96 97 @Override 98 public String expand(String optParameter) { 99 return retStr; 100 } 101 } 102 103 enum TypeArgumentKind implements ComboParameter { 104 NONE(""), 105 UNBOUND("<?>"), 106 INTEGER("<Number>"), 107 NUMBER("<Integer>"), 108 TYPEVAR("<X>"); 109 110 String typeargStr; 111 112 TypeArgumentKind(String typeargStr) { 113 this.typeargStr = typeargStr; 114 } 115 116 boolean compatibleWith(SignatureKind sig) { 117 switch (this) { 118 case TYPEVAR: return sig != SignatureKind.NON_GENERIC; 119 default: return true; 120 } 121 } 122 123 boolean moreSpecificThan(TypeArgumentKind that, boolean strict) { 124 switch (this) { 125 case NONE: 126 return that == this || !strict; 127 case UNBOUND: 128 return that == this || that == NONE; 129 case INTEGER: 130 case NUMBER: 131 case TYPEVAR: 132 return that == this || that == NONE || that == UNBOUND; 133 default: throw new AssertionError("Unexpected typearg kind: " + this); 134 } 135 } 136 137 boolean assignableTo(TypeArgumentKind that, SignatureKind sig, SourceLevel level) { 138 switch (this) { 139 case NONE: 140 //this case needs to workaround to javac's impl of 15.12.2.8 being too strict 141 //ideally should be just 'return true' (see 7067746/8015505) 142 return level == SourceLevel.SOURCE_DEFAULT || 143 sig == SignatureKind.NON_GENERIC || that == NONE; 144 case UNBOUND: 145 return that == this || that == NONE; 146 case INTEGER: 147 case NUMBER: 148 return that == this || that == NONE || that == UNBOUND; 149 case TYPEVAR: 150 return true; 151 default: throw new AssertionError("Unexpected typearg kind: " + this); 152 } 153 } 154 155 @Override 156 public String expand(String optParameter) { 157 return typeargStr; 158 } 159 } 160 161 public static void main(String... args) throws Exception { 162 new ComboTestHelper<GenericOverrideTest>() 163 .withFilter(GenericOverrideTest::argMismatchFilter) 164 .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values()) 165 .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values()) 166 .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values()) 167 .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values()) 168 .run(GenericOverrideTest::new); 169 } 170 171 SignatureKind[] sigs = new SignatureKind[2]; 172 ReturnTypeKind[] rets = new ReturnTypeKind[3]; 173 TypeArgumentKind[] targs = new TypeArgumentKind[3]; 174 SourceLevel level; 175 176 boolean argMismatchFilter() { 177 return targs[0].compatibleWith(sigs[0]) && 178 targs[1].compatibleWith(sigs[1]) && 179 targs[2].compatibleWith(SignatureKind.NON_GENERIC); 180 } 181 182 String template = "import java.util.*;\n" + 183 "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" + 184 "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" + 185 "interface AB extends A, B {}\n" + 186 "class Test {\n" + 187 " void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" + 188 "}"; 189 190 @Override 191 public void doWork() throws IOException { 192 check(newCompilationTask() 193 .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes! 194 .withOptions(level.opts) 195 .withSourceFromTemplate(template) 196 .analyze()); 197 } 198 199 void check(Result<?> res) { 200 boolean errorExpected = false; 201 int mostSpecific = 0; 202 203 //first check that either |R1| <: |R2| or |R2| <: |R1| 204 if (rets[0] != rets[1]) { 205 if (!rets[0].moreSpecificThan(rets[1]) && 206 !rets[1].moreSpecificThan(rets[0])) { 207 errorExpected = true; 208 } else { 209 mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2; 210 } 211 } 212 213 //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw) 214 if (!errorExpected) { 215 if (targs[0] != targs[1]) { 216 boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) || 217 targs[1].moreSpecificThan(targs[0], true); 218 if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) && 219 !targs[1].moreSpecificThan(targs[0], useStrictCheck)) { 220 errorExpected = true; 221 } else { 222 int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2; 223 if (mostSpecific != 0 && mostSpecific2 != mostSpecific) { 224 errorExpected = mostSpecific == 1 ? 225 targs[0] != TypeArgumentKind.NONE : 226 targs[1] != TypeArgumentKind.NONE; 227 } else { 228 mostSpecific = mostSpecific2; 229 } 230 } 231 } else if (mostSpecific == 0) { 232 //when no signature is better than the other, an arbitrary choice 233 //must be made - javac always picks the second signature 234 mostSpecific = 2; 235 } 236 } 237 238 //finally, check that most specific return type is compatible with expected type 239 if (!errorExpected) { 240 ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1]; 241 TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1]; 242 SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1]; 243 244 if (!msrt.moreSpecificThan(rets[2]) || 245 !msta.assignableTo(targs[2], mssig, level)) { 246 errorExpected = true; 247 } 248 } 249 250 if (errorExpected != res.hasErrors()) { 251 fail("invalid diagnostics for source:\n" + 252 res.compilationInfo() + 253 "\nFound error: " + res.hasErrors() + 254 "\nExpected error: " + errorExpected); 255 } 256 } 257} 258