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