21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 7062745 8006694 |
26 * @bug 7062745 8006694 8129962 |
27 * @summary Regression: difference in overload resolution when two methods |
27 * @summary Regression: difference in overload resolution when two methods |
28 * are maximally specific |
28 * are maximally specific |
29 * temporarily workaround combo tests are causing time out in several platforms |
29 * temporarily workaround combo tests are causing time out in several platforms |
30 * @library ../../../lib |
30 * @library /tools/javac/lib |
31 * @modules jdk.compiler |
31 * @modules jdk.compiler/com.sun.tools.javac.api |
32 * @build JavacTestingAbstractThreadedTest |
32 * jdk.compiler/com.sun.tools.javac.code |
33 * @run main/othervm GenericOverrideTest |
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 |
34 */ |
39 */ |
35 |
40 |
36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) |
41 import java.io.IOException; |
37 // see JDK-8006746 |
42 |
38 |
43 import combo.ComboInstance; |
39 import java.net.URI; |
44 import combo.ComboParameter; |
40 import java.util.Arrays; |
45 import combo.ComboTask.Result; |
41 import javax.tools.Diagnostic; |
46 import combo.ComboTestHelper; |
42 import javax.tools.JavaFileObject; |
47 |
43 import javax.tools.SimpleJavaFileObject; |
48 public class GenericOverrideTest extends ComboInstance<GenericOverrideTest> { |
44 import com.sun.source.util.JavacTask; |
|
45 |
|
46 public class GenericOverrideTest |
|
47 extends JavacTestingAbstractThreadedTest |
|
48 implements Runnable { |
|
49 |
49 |
50 enum SourceLevel { |
50 enum SourceLevel { |
51 SOURCE_7("-source", "7"), |
51 SOURCE_7("-source", "7"), |
52 SOURCE_DEFAULT(); |
52 SOURCE_DEFAULT(); |
53 |
53 |
139 case TYPEVAR: |
149 case TYPEVAR: |
140 return true; |
150 return true; |
141 default: throw new AssertionError("Unexpected typearg kind: " + this); |
151 default: throw new AssertionError("Unexpected typearg kind: " + this); |
142 } |
152 } |
143 } |
153 } |
|
154 |
|
155 @Override |
|
156 public String expand(String optParameter) { |
|
157 return typeargStr; |
|
158 } |
144 } |
159 } |
145 |
160 |
146 public static void main(String... args) throws Exception { |
161 public static void main(String... args) throws Exception { |
147 for (SignatureKind sig1 : SignatureKind.values()) { |
162 new ComboTestHelper<GenericOverrideTest>() |
148 for (ReturnTypeKind rt1 : ReturnTypeKind.values()) { |
163 .withFilter(GenericOverrideTest::argMismatchFilter) |
149 for (TypeArgumentKind ta1 : TypeArgumentKind.values()) { |
164 .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values()) |
150 if (!ta1.compatibleWith(sig1)) continue; |
165 .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values()) |
151 for (SignatureKind sig2 : SignatureKind.values()) { |
166 .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values()) |
152 for (ReturnTypeKind rt2 : ReturnTypeKind.values()) { |
167 .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values()) |
153 for (TypeArgumentKind ta2 : TypeArgumentKind.values()) { |
168 .run(GenericOverrideTest::new); |
154 if (!ta2.compatibleWith(sig2)) continue; |
169 } |
155 for (ReturnTypeKind rt3 : ReturnTypeKind.values()) { |
170 |
156 for (TypeArgumentKind ta3 : TypeArgumentKind.values()) { |
171 SignatureKind[] sigs = new SignatureKind[2]; |
157 if (!ta3.compatibleWith(SignatureKind.NON_GENERIC)) |
172 ReturnTypeKind[] rets = new ReturnTypeKind[3]; |
158 continue; |
173 TypeArgumentKind[] targs = new TypeArgumentKind[3]; |
159 for (SourceLevel level : SourceLevel.values()) { |
|
160 pool.execute( |
|
161 new GenericOverrideTest(sig1, |
|
162 rt1, ta1, sig2, rt2, |
|
163 ta2, rt3, ta3, level)); |
|
164 } |
|
165 } |
|
166 } |
|
167 } |
|
168 } |
|
169 } |
|
170 } |
|
171 } |
|
172 } |
|
173 |
|
174 checkAfterExec(); |
|
175 } |
|
176 |
|
177 SignatureKind sig1, sig2; |
|
178 ReturnTypeKind rt1, rt2, rt3; |
|
179 TypeArgumentKind ta1, ta2, ta3; |
|
180 SourceLevel level; |
174 SourceLevel level; |
181 JavaSource source; |
175 |
182 DiagnosticChecker diagChecker; |
176 boolean argMismatchFilter() { |
183 |
177 return targs[0].compatibleWith(sigs[0]) && |
184 GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1, |
178 targs[1].compatibleWith(sigs[1]) && |
185 SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2, |
179 targs[2].compatibleWith(SignatureKind.NON_GENERIC); |
186 ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) { |
180 } |
187 this.sig1 = sig1; |
181 |
188 this.sig2 = sig2; |
182 String template = "import java.util.*;\n" + |
189 this.rt1 = rt1; |
183 "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" + |
190 this.rt2 = rt2; |
184 "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" + |
191 this.rt3 = rt3; |
185 "interface AB extends A, B {}\n" + |
192 this.ta1 = ta1; |
186 "class Test {\n" + |
193 this.ta2 = ta2; |
187 " void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" + |
194 this.ta3 = ta3; |
188 "}"; |
195 this.level = level; |
|
196 this.source = new JavaSource(); |
|
197 this.diagChecker = new DiagnosticChecker(); |
|
198 } |
|
199 |
|
200 class JavaSource extends SimpleJavaFileObject { |
|
201 |
|
202 String template = "import java.util.*;\n" + |
|
203 "interface A { #S1 #R1#TA1 m(); }\n" + |
|
204 "interface B { #S2 #R2#TA2 m(); }\n" + |
|
205 "interface AB extends A, B {}\n" + |
|
206 "class Test {\n" + |
|
207 " void test(AB ab) { #R3#TA3 n = ab.m(); }\n" + |
|
208 "}"; |
|
209 |
|
210 String source; |
|
211 |
|
212 public JavaSource() { |
|
213 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
|
214 source = template.replace("#S1", sig1.paramStr). |
|
215 replace("#S2", sig2.paramStr). |
|
216 replace("#R1", rt1.retStr). |
|
217 replace("#R2", rt2.retStr). |
|
218 replace("#R3", rt3.retStr). |
|
219 replace("#TA1", ta1.typeargStr). |
|
220 replace("#TA2", ta2.typeargStr). |
|
221 replace("#TA3", ta3.typeargStr); |
|
222 } |
|
223 |
|
224 @Override |
|
225 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
|
226 return source; |
|
227 } |
|
228 } |
|
229 |
189 |
230 @Override |
190 @Override |
231 public void run() { |
191 public void doWork() throws IOException { |
232 JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, |
192 check(newCompilationTask() |
233 level.opts != null ? Arrays.asList(level.opts) : null, |
193 .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes! |
234 null, Arrays.asList(source)); |
194 .withOptions(level.opts) |
235 try { |
195 .withSourceFromTemplate(template) |
236 ct.analyze(); |
196 .analyze()); |
237 } catch (Throwable ex) { |
197 } |
238 throw new AssertionError("Error thrown when compiling the following code:\n" + |
198 |
239 source.getCharContent(true)); |
199 void check(Result<?> res) { |
240 } |
|
241 check(); |
|
242 } |
|
243 |
|
244 void check() { |
|
245 checkCount.incrementAndGet(); |
|
246 |
|
247 boolean errorExpected = false; |
200 boolean errorExpected = false; |
248 int mostSpecific = 0; |
201 int mostSpecific = 0; |
249 |
202 |
250 //first check that either |R1| <: |R2| or |R2| <: |R1| |
203 //first check that either |R1| <: |R2| or |R2| <: |R1| |
251 if (rt1 != rt2) { |
204 if (rets[0] != rets[1]) { |
252 if (!rt1.moreSpecificThan(rt2) && |
205 if (!rets[0].moreSpecificThan(rets[1]) && |
253 !rt2.moreSpecificThan(rt1)) { |
206 !rets[1].moreSpecificThan(rets[0])) { |
254 errorExpected = true; |
207 errorExpected = true; |
255 } else { |
208 } else { |
256 mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2; |
209 mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2; |
257 } |
210 } |
258 } |
211 } |
259 |
212 |
260 //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw) |
213 //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw) |
261 if (!errorExpected) { |
214 if (!errorExpected) { |
262 if (ta1 != ta2) { |
215 if (targs[0] != targs[1]) { |
263 boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) || |
216 boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) || |
264 ta2.moreSpecificThan(ta1, true); |
217 targs[1].moreSpecificThan(targs[0], true); |
265 if (!ta1.moreSpecificThan(ta2, useStrictCheck) && |
218 if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) && |
266 !ta2.moreSpecificThan(ta1, useStrictCheck)) { |
219 !targs[1].moreSpecificThan(targs[0], useStrictCheck)) { |
267 errorExpected = true; |
220 errorExpected = true; |
268 } else { |
221 } else { |
269 int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2; |
222 int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2; |
270 if (mostSpecific != 0 && mostSpecific2 != mostSpecific) { |
223 if (mostSpecific != 0 && mostSpecific2 != mostSpecific) { |
271 errorExpected = mostSpecific == 1 ? |
224 errorExpected = mostSpecific == 1 ? |
272 ta1 != TypeArgumentKind.NONE : |
225 targs[0] != TypeArgumentKind.NONE : |
273 ta2 != TypeArgumentKind.NONE; |
226 targs[1] != TypeArgumentKind.NONE; |
274 } else { |
227 } else { |
275 mostSpecific = mostSpecific2; |
228 mostSpecific = mostSpecific2; |
276 } |
229 } |
277 } |
230 } |
278 } else if (mostSpecific == 0) { |
231 } else if (mostSpecific == 0) { |
282 } |
235 } |
283 } |
236 } |
284 |
237 |
285 //finally, check that most specific return type is compatible with expected type |
238 //finally, check that most specific return type is compatible with expected type |
286 if (!errorExpected) { |
239 if (!errorExpected) { |
287 ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2; |
240 ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1]; |
288 TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2; |
241 TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1]; |
289 SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2; |
242 SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1]; |
290 |
243 |
291 if (!msrt.moreSpecificThan(rt3) || |
244 if (!msrt.moreSpecificThan(rets[2]) || |
292 !msta.assignableTo(ta3, mssig, level)) { |
245 !msta.assignableTo(targs[2], mssig, level)) { |
293 errorExpected = true; |
246 errorExpected = true; |
294 } |
247 } |
295 } |
248 } |
296 |
249 |
297 if (errorExpected != diagChecker.errorFound) { |
250 if (errorExpected != res.hasErrors()) { |
298 throw new Error("invalid diagnostics for source:\n" + |
251 fail("invalid diagnostics for source:\n" + |
299 source.getCharContent(true) + |
252 res.compilationInfo() + |
300 "\nFound error: " + diagChecker.errorFound + |
253 "\nFound error: " + res.hasErrors() + |
301 "\nExpected error: " + errorExpected); |
254 "\nExpected error: " + errorExpected); |
302 } |
255 } |
303 } |
256 } |
304 |
|
305 static class DiagnosticChecker |
|
306 implements javax.tools.DiagnosticListener<JavaFileObject> { |
|
307 |
|
308 boolean errorFound; |
|
309 |
|
310 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
|
311 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { |
|
312 errorFound = true; |
|
313 } |
|
314 } |
|
315 } |
|
316 |
|
317 } |
257 } |