test/tools/javac/cast/intersection/IntersectionTypeCastTest.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
1 /*
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.
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 8002099 8006694
27 * @summary Add support for intersection types in cast expression
28 * temporarily workaround combo tests are causing time out in several platforms
29 * @library ../../lib
30 * @build JavacTestingAbstractThreadedTest
31 * @run main/othervm/timeout=360 IntersectionTypeCastTest
32 */
33
34 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
35 // see JDK-8006746
36
37 import java.net.URI;
38 import java.util.Arrays;
39 import javax.tools.Diagnostic;
40 import javax.tools.JavaCompiler;
41 import javax.tools.JavaFileObject;
42 import javax.tools.SimpleJavaFileObject;
43 import javax.tools.ToolProvider;
44
45 import com.sun.source.util.JavacTask;
46 import com.sun.tools.javac.util.List;
47 import com.sun.tools.javac.util.ListBuffer;
48
49 public class IntersectionTypeCastTest
50 extends JavacTestingAbstractThreadedTest
51 implements Runnable {
52
53 interface Type {
54 boolean subtypeOf(Type that);
55 String asString();
56 boolean isClass();
57 boolean isInterface();
58 }
59
60 enum InterfaceKind implements Type {
61 A("interface A { }\n", "A", null),
62 B("interface B { }\n", "B", null),
63 C("interface C extends A { }\n", "C", A);
64
65 String declStr;
66 String typeStr;
67 InterfaceKind superInterface;
68
69 InterfaceKind(String declStr, String typeStr,
70 InterfaceKind superInterface) {
71 this.declStr = declStr;
72 this.typeStr = typeStr;
73 this.superInterface = superInterface;
74 }
75
76 @Override
77 public boolean subtypeOf(Type that) {
78 return this == that || superInterface == that ||
79 that == ClassKind.OBJECT;
80 }
81
82 @Override
83 public String asString() {
84 return typeStr;
85 }
86
87 @Override
88 public boolean isClass() {
89 return false;
90 }
91
92 @Override
93 public boolean isInterface() {
94 return true;
95 }
96 }
97
98 enum ClassKind implements Type {
99 OBJECT(null, "Object"),
100 CA("#M class CA implements A { }\n", "CA",
101 InterfaceKind.A),
102 CB("#M class CB implements B { }\n", "CB",
103 InterfaceKind.B),
104 CAB("#M class CAB implements A, B { }\n", "CAB",
105 InterfaceKind.A, InterfaceKind.B),
106 CC("#M class CC implements C { }\n", "CC",
107 InterfaceKind.C, InterfaceKind.A),
108 CCA("#M class CCA implements C, A { }\n", "CCA",
109 InterfaceKind.C, InterfaceKind.A),
110 CCB("#M class CCB implements C, B { }\n", "CCB",
111 InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
112 CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
113 InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
114
115 String declTemplate;
116 String typeStr;
117 List<InterfaceKind> superInterfaces;
118
119 ClassKind(String declTemplate, String typeStr,
120 InterfaceKind... superInterfaces) {
121 this.declTemplate = declTemplate;
122 this.typeStr = typeStr;
123 this.superInterfaces = List.from(superInterfaces);
124 }
125
126 String getDecl(ModifierKind mod) {
127 return declTemplate != null ?
128 declTemplate.replaceAll("#M", mod.modStr) :
129 "";
130 }
131
132 @Override
133 public boolean subtypeOf(Type that) {
134 return this == that || superInterfaces.contains(that) ||
135 that == OBJECT;
136 }
137
138 @Override
139 public String asString() {
140 return typeStr;
141 }
142
143 @Override
144 public boolean isClass() {
145 return true;
146 }
147
148 @Override
149 public boolean isInterface() {
150 return false;
151 }
152 }
153
154 enum ModifierKind {
155 NONE(""),
156 FINAL("final");
157
158 String modStr;
159
160 ModifierKind(String modStr) {
161 this.modStr = modStr;
162 }
163 }
164
165 enum CastKind {
166 CLASS("(#C)", 0),
167 INTERFACE("(#I0)", 1),
168 INTERSECTION2("(#C & #I0)", 1),
169 INTERSECTION3("(#C & #I0 & #I1)", 2);
170 //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3);
171
172 String castTemplate;
173 int interfaceBounds;
174
175 CastKind(String castTemplate, int interfaceBounds) {
176 this.castTemplate = castTemplate;
177 this.interfaceBounds = interfaceBounds;
178 }
179 }
180
181 static class CastInfo {
182 CastKind kind;
183 Type[] types;
184
185 CastInfo(CastKind kind, Type... types) {
186 this.kind = kind;
187 this.types = types;
188 }
189
190 String getCast() {
191 String temp = kind.castTemplate.replaceAll("#C",
192 types[0].asString());
193 for (int i = 0; i < kind.interfaceBounds ; i++) {
194 temp = temp.replace(String.format("#I%d", i),
195 types[i + 1].asString());
196 }
197 return temp;
198 }
199
200 boolean hasDuplicateTypes() {
201 for (int i = 0 ; i < types.length ; i++) {
202 for (int j = 0 ; j < types.length ; j++) {
203 if (i != j && types[i] == types[j]) {
204 return true;
205 }
206 }
207 }
208 return false;
209 }
210
211 boolean compatibleWith(ModifierKind mod, CastInfo that) {
212 for (Type t1 : types) {
213 for (Type t2 : that.types) {
214 boolean compat =
215 t1.subtypeOf(t2) ||
216 t2.subtypeOf(t1) ||
217 (t1.isInterface() && t2.isInterface()) || //side-cast (1)
218 (mod == ModifierKind.NONE &&
219 (t1.isInterface() != t2.isInterface())); //side-cast (2)
220 if (!compat) return false;
221 }
222 }
223 return true;
224 }
225 }
226
227 public static void main(String... args) throws Exception {
228 for (ModifierKind mod : ModifierKind.values()) {
229 for (CastInfo cast1 : allCastInfo()) {
230 for (CastInfo cast2 : allCastInfo()) {
231 pool.execute(
232 new IntersectionTypeCastTest(mod, cast1, cast2));
233 }
234 }
235 }
236 checkAfterExec();
237 }
238
239 static List<CastInfo> allCastInfo() {
240 ListBuffer<CastInfo> buf = new ListBuffer<>();
241 for (CastKind kind : CastKind.values()) {
242 for (ClassKind clazz : ClassKind.values()) {
243 if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) {
244 continue;
245 } else if (kind.interfaceBounds == 0) {
246 buf.append(new CastInfo(kind, clazz));
247 continue;
248 } else {
249 for (InterfaceKind intf1 : InterfaceKind.values()) {
250 if (kind.interfaceBounds == 1) {
251 buf.append(new CastInfo(kind, clazz, intf1));
252 continue;
253 } else {
254 for (InterfaceKind intf2 : InterfaceKind.values()) {
255 if (kind.interfaceBounds == 2) {
256 buf.append(
257 new CastInfo(kind, clazz, intf1, intf2));
258 continue;
259 } else {
260 for (InterfaceKind intf3 : InterfaceKind.values()) {
261 buf.append(
262 new CastInfo(kind, clazz, intf1,
263 intf2, intf3));
264 continue;
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273 return buf.toList();
274 }
275
276 ModifierKind mod;
277 CastInfo cast1, cast2;
278 JavaSource source;
279 DiagnosticChecker diagChecker;
280
281 IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) {
282 this.mod = mod;
283 this.cast1 = cast1;
284 this.cast2 = cast2;
285 this.source = new JavaSource();
286 this.diagChecker = new DiagnosticChecker();
287 }
288
289 @Override
290 public void run() {
291 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
292
293 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
294 null, null, Arrays.asList(source));
295 try {
296 ct.analyze();
297 } catch (Throwable ex) {
298 throw new AssertionError("Error thrown when compiling the following code:\n" +
299 source.getCharContent(true));
300 }
301 check();
302 }
303
304 class JavaSource extends SimpleJavaFileObject {
305
306 String bodyTemplate = "class Test {\n" +
307 " void test() {\n" +
308 " Object o = #C1#C2null;\n" +
309 " } }";
310
311 String source = "";
312
313 public JavaSource() {
314 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
315 for (ClassKind ck : ClassKind.values()) {
316 source += ck.getDecl(mod);
317 }
318 for (InterfaceKind ik : InterfaceKind.values()) {
319 source += ik.declStr;
320 }
321 source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
322 replaceAll("#C2", cast2.getCast());
323 }
324
325 @Override
326 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
327 return source;
328 }
329 }
330
331 void check() {
332 checkCount.incrementAndGet();
333
334 boolean errorExpected = cast1.hasDuplicateTypes() ||
335 cast2.hasDuplicateTypes();
336
337 errorExpected |= !cast2.compatibleWith(mod, cast1);
338
339 if (errorExpected != diagChecker.errorFound) {
340 throw new Error("invalid diagnostics for source:\n" +
341 source.getCharContent(true) +
342 "\nFound error: " + diagChecker.errorFound +
343 "\nExpected error: " + errorExpected);
344 }
345 }
346
347 static class DiagnosticChecker
348 implements javax.tools.DiagnosticListener<JavaFileObject> {
349
350 boolean errorFound;
351
352 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
353 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
354 errorFound = true;
355 }
356 }
357 }
358
359 }

mercurial