1 /* |
1 /* |
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 8002099 |
26 * @bug 8002099 |
27 * @summary Add support for intersection types in cast expression |
27 * @summary Add support for intersection types in cast expression |
|
28 * @library ../../lib |
|
29 * @build JavacTestingAbstractThreadedTest |
|
30 * @run main/timeout=360 IntersectionTypeCastTest |
28 */ |
31 */ |
29 |
32 |
30 import com.sun.source.util.JavacTask; |
|
31 import com.sun.tools.javac.util.List; |
|
32 import com.sun.tools.javac.util.ListBuffer; |
|
33 import java.net.URI; |
33 import java.net.URI; |
34 import java.util.Arrays; |
34 import java.util.Arrays; |
35 import javax.tools.Diagnostic; |
35 import javax.tools.Diagnostic; |
36 import javax.tools.JavaCompiler; |
36 import javax.tools.JavaCompiler; |
37 import javax.tools.JavaFileObject; |
37 import javax.tools.JavaFileObject; |
38 import javax.tools.SimpleJavaFileObject; |
38 import javax.tools.SimpleJavaFileObject; |
39 import javax.tools.StandardJavaFileManager; |
|
40 import javax.tools.ToolProvider; |
39 import javax.tools.ToolProvider; |
41 |
40 |
42 public class IntersectionTypeCastTest { |
41 import com.sun.source.util.JavacTask; |
43 |
42 import com.sun.tools.javac.util.List; |
44 static int checkCount = 0; |
43 import com.sun.tools.javac.util.ListBuffer; |
|
44 |
|
45 public class IntersectionTypeCastTest |
|
46 extends JavacTestingAbstractThreadedTest |
|
47 implements Runnable { |
45 |
48 |
46 interface Type { |
49 interface Type { |
47 boolean subtypeOf(Type that); |
50 boolean subtypeOf(Type that); |
48 String asString(); |
51 String asString(); |
49 boolean isClass(); |
52 boolean isClass(); |
57 |
60 |
58 String declStr; |
61 String declStr; |
59 String typeStr; |
62 String typeStr; |
60 InterfaceKind superInterface; |
63 InterfaceKind superInterface; |
61 |
64 |
62 InterfaceKind(String declStr, String typeStr, InterfaceKind superInterface) { |
65 InterfaceKind(String declStr, String typeStr, |
|
66 InterfaceKind superInterface) { |
63 this.declStr = declStr; |
67 this.declStr = declStr; |
64 this.typeStr = typeStr; |
68 this.typeStr = typeStr; |
65 this.superInterface = superInterface; |
69 this.superInterface = superInterface; |
66 } |
70 } |
67 |
71 |
68 @Override |
72 @Override |
69 public boolean subtypeOf(Type that) { |
73 public boolean subtypeOf(Type that) { |
70 return this == that || superInterface == that || that == ClassKind.OBJECT; |
74 return this == that || superInterface == that || |
|
75 that == ClassKind.OBJECT; |
71 } |
76 } |
72 |
77 |
73 @Override |
78 @Override |
74 public String asString() { |
79 public String asString() { |
75 return typeStr; |
80 return typeStr; |
86 } |
91 } |
87 } |
92 } |
88 |
93 |
89 enum ClassKind implements Type { |
94 enum ClassKind implements Type { |
90 OBJECT(null, "Object"), |
95 OBJECT(null, "Object"), |
91 CA("#M class CA implements A { }\n", "CA", InterfaceKind.A), |
96 CA("#M class CA implements A { }\n", "CA", |
92 CB("#M class CB implements B { }\n", "CB", InterfaceKind.B), |
97 InterfaceKind.A), |
93 CAB("#M class CAB implements A, B { }\n", "CAB", InterfaceKind.A, InterfaceKind.B), |
98 CB("#M class CB implements B { }\n", "CB", |
94 CC("#M class CC implements C { }\n", "CC", InterfaceKind.C, InterfaceKind.A), |
99 InterfaceKind.B), |
95 CCA("#M class CCA implements C, A { }\n", "CCA", InterfaceKind.C, InterfaceKind.A), |
100 CAB("#M class CAB implements A, B { }\n", "CAB", |
96 CCB("#M class CCB implements C, B { }\n", "CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), |
101 InterfaceKind.A, InterfaceKind.B), |
97 CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); |
102 CC("#M class CC implements C { }\n", "CC", |
|
103 InterfaceKind.C, InterfaceKind.A), |
|
104 CCA("#M class CCA implements C, A { }\n", "CCA", |
|
105 InterfaceKind.C, InterfaceKind.A), |
|
106 CCB("#M class CCB implements C, B { }\n", "CCB", |
|
107 InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), |
|
108 CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", |
|
109 InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); |
98 |
110 |
99 String declTemplate; |
111 String declTemplate; |
100 String typeStr; |
112 String typeStr; |
101 List<InterfaceKind> superInterfaces; |
113 List<InterfaceKind> superInterfaces; |
102 |
114 |
103 ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) { |
115 ClassKind(String declTemplate, String typeStr, |
|
116 InterfaceKind... superInterfaces) { |
104 this.declTemplate = declTemplate; |
117 this.declTemplate = declTemplate; |
105 this.typeStr = typeStr; |
118 this.typeStr = typeStr; |
106 this.superInterfaces = List.from(superInterfaces); |
119 this.superInterfaces = List.from(superInterfaces); |
107 } |
120 } |
108 |
121 |
193 for (Type t2 : that.types) { |
209 for (Type t2 : that.types) { |
194 boolean compat = |
210 boolean compat = |
195 t1.subtypeOf(t2) || |
211 t1.subtypeOf(t2) || |
196 t2.subtypeOf(t1) || |
212 t2.subtypeOf(t1) || |
197 (t1.isInterface() && t2.isInterface()) || //side-cast (1) |
213 (t1.isInterface() && t2.isInterface()) || //side-cast (1) |
198 (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2) |
214 (mod == ModifierKind.NONE && |
|
215 (t1.isInterface() != t2.isInterface())); //side-cast (2) |
199 if (!compat) return false; |
216 if (!compat) return false; |
200 } |
217 } |
201 } |
218 } |
202 return true; |
219 return true; |
203 } |
220 } |
204 } |
221 } |
205 |
222 |
206 public static void main(String... args) throws Exception { |
223 public static void main(String... args) throws Exception { |
207 //create default shared JavaCompiler - reused across multiple compilations |
|
208 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); |
|
209 StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); |
|
210 |
|
211 for (ModifierKind mod : ModifierKind.values()) { |
224 for (ModifierKind mod : ModifierKind.values()) { |
212 for (CastInfo cast1 : allCastInfo()) { |
225 for (CastInfo cast1 : allCastInfo()) { |
213 for (CastInfo cast2 : allCastInfo()) { |
226 for (CastInfo cast2 : allCastInfo()) { |
214 new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm); |
227 pool.execute( |
|
228 new IntersectionTypeCastTest(mod, cast1, cast2)); |
215 } |
229 } |
216 } |
230 } |
217 } |
231 } |
218 System.out.println("Total check executed: " + checkCount); |
232 checkAfterExec(); |
219 } |
233 } |
220 |
234 |
221 static List<CastInfo> allCastInfo() { |
235 static List<CastInfo> allCastInfo() { |
222 ListBuffer<CastInfo> buf = ListBuffer.lb(); |
236 ListBuffer<CastInfo> buf = ListBuffer.lb(); |
223 for (CastKind kind : CastKind.values()) { |
237 for (CastKind kind : CastKind.values()) { |
233 buf.append(new CastInfo(kind, clazz, intf1)); |
247 buf.append(new CastInfo(kind, clazz, intf1)); |
234 continue; |
248 continue; |
235 } else { |
249 } else { |
236 for (InterfaceKind intf2 : InterfaceKind.values()) { |
250 for (InterfaceKind intf2 : InterfaceKind.values()) { |
237 if (kind.interfaceBounds == 2) { |
251 if (kind.interfaceBounds == 2) { |
238 buf.append(new CastInfo(kind, clazz, intf1, intf2)); |
252 buf.append( |
|
253 new CastInfo(kind, clazz, intf1, intf2)); |
239 continue; |
254 continue; |
240 } else { |
255 } else { |
241 for (InterfaceKind intf3 : InterfaceKind.values()) { |
256 for (InterfaceKind intf3 : InterfaceKind.values()) { |
242 buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3)); |
257 buf.append( |
|
258 new CastInfo(kind, clazz, intf1, |
|
259 intf2, intf3)); |
243 continue; |
260 continue; |
244 } |
261 } |
245 } |
262 } |
246 } |
263 } |
247 } |
264 } |
263 this.cast2 = cast2; |
280 this.cast2 = cast2; |
264 this.source = new JavaSource(); |
281 this.source = new JavaSource(); |
265 this.diagChecker = new DiagnosticChecker(); |
282 this.diagChecker = new DiagnosticChecker(); |
266 } |
283 } |
267 |
284 |
|
285 @Override |
|
286 public void run() { |
|
287 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
|
288 |
|
289 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, |
|
290 Arrays.asList("-XDallowIntersectionTypes"), |
|
291 null, Arrays.asList(source)); |
|
292 try { |
|
293 ct.analyze(); |
|
294 } catch (Throwable ex) { |
|
295 throw new AssertionError("Error thrown when compiling the following code:\n" + |
|
296 source.getCharContent(true)); |
|
297 } |
|
298 check(); |
|
299 } |
|
300 |
268 class JavaSource extends SimpleJavaFileObject { |
301 class JavaSource extends SimpleJavaFileObject { |
269 |
302 |
270 String bodyTemplate = "class Test {\n" + |
303 String bodyTemplate = "class Test {\n" + |
271 " void test() {\n" + |
304 " void test() {\n" + |
272 " Object o = #C1#C2null;\n" + |
305 " Object o = #C1#C2null;\n" + |
280 source += ck.getDecl(mod); |
313 source += ck.getDecl(mod); |
281 } |
314 } |
282 for (InterfaceKind ik : InterfaceKind.values()) { |
315 for (InterfaceKind ik : InterfaceKind.values()) { |
283 source += ik.declStr; |
316 source += ik.declStr; |
284 } |
317 } |
285 source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast()); |
318 source += bodyTemplate.replaceAll("#C1", cast1.getCast()). |
|
319 replaceAll("#C2", cast2.getCast()); |
286 } |
320 } |
287 |
321 |
288 @Override |
322 @Override |
289 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
323 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
290 return source; |
324 return source; |
291 } |
325 } |
292 } |
326 } |
293 |
327 |
294 void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { |
|
295 JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, |
|
296 Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); |
|
297 try { |
|
298 ct.analyze(); |
|
299 } catch (Throwable ex) { |
|
300 throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); |
|
301 } |
|
302 check(); |
|
303 } |
|
304 |
|
305 void check() { |
328 void check() { |
306 checkCount++; |
329 checkCount.incrementAndGet(); |
307 |
330 |
308 boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes(); |
331 boolean errorExpected = cast1.hasDuplicateTypes() || |
|
332 cast2.hasDuplicateTypes(); |
309 |
333 |
310 errorExpected |= !cast2.compatibleWith(mod, cast1); |
334 errorExpected |= !cast2.compatibleWith(mod, cast1); |
311 |
335 |
312 if (errorExpected != diagChecker.errorFound) { |
336 if (errorExpected != diagChecker.errorFound) { |
313 throw new Error("invalid diagnostics for source:\n" + |
337 throw new Error("invalid diagnostics for source:\n" + |