Tue, 08 Jan 2013 13:47:57 +0000
8005167: execution time of combo tests in javac should be improved
Reviewed-by: jjg, jjh
1 /*
2 * Copyright (c) 2011, 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 8003280
27 * @summary Add lambda tests
28 * perform automated checks in type inference in lambda expressions
29 * in different contexts
30 * @library ../../../lib
31 * @build JavacTestingAbstractThreadedTest
32 * @compile TypeInferenceComboTest.java
33 * @run main/timeout=360 TypeInferenceComboTest
34 */
36 import java.net.URI;
37 import java.util.Arrays;
38 import javax.tools.Diagnostic;
39 import javax.tools.JavaFileObject;
40 import javax.tools.SimpleJavaFileObject;
41 import com.sun.source.util.JavacTask;
43 public class TypeInferenceComboTest
44 extends JavacTestingAbstractThreadedTest
45 implements Runnable {
46 enum Context {
47 ASSIGNMENT("SAM#Type s = #LBody;"),
48 METHOD_CALL("#GenericDeclKind void method1(SAM#Type s) { }\n" +
49 "void method2() {\n" +
50 " method1(#LBody);\n" +
51 "}"),
52 RETURN_OF_METHOD("SAM#Type method1() {\n" +
53 " return #LBody;\n" +
54 "}"),
55 LAMBDA_RETURN_EXPRESSION("SAM2 s2 = () -> {return (SAM#Type)#LBody;};\n"),
56 ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (SAM#Type)#LBody};");
58 String context;
60 Context(String context) {
61 this.context = context;
62 }
64 String getContext(SamKind sk, TypeKind samTargetT, Keyword kw,
65 TypeKind parameterT, TypeKind returnT, LambdaKind lk,
66 ParameterKind pk, GenericDeclKind gdk, LambdaBody lb) {
67 String result = context;
68 if (sk == SamKind.GENERIC) {
69 if(this == Context.METHOD_CALL) {
70 result = result.replaceAll("#GenericDeclKind",
71 gdk.getGenericDeclKind(samTargetT));
72 if(gdk == GenericDeclKind.NON_GENERIC)
73 result = result.replaceAll("#Type", "<" +
74 samTargetT.typeStr + ">");
75 else //#GenericDeclKind is <T> or <T extends xxx>
76 result = result.replaceAll("#Type", "<T>");
77 }
78 else {
79 if(kw == Keyword.VOID)
80 result = result.replaceAll("#Type", "<" +
81 samTargetT.typeStr + ">");
82 else
83 result = result.replaceAll("#Type", "<? " + kw.keyStr +
84 " " + samTargetT.typeStr + ">");
85 }
86 }
87 else
88 result = result.replaceAll("#Type", "").
89 replaceAll("#GenericDeclKind", "");
91 return result.replaceAll("#LBody",
92 lb.getLambdaBody(samTargetT, parameterT, returnT, lk, pk));
93 }
94 }
96 enum SamKind {
97 GENERIC("interface SAM<T> { #R m(#ARG); }"),
98 NON_GENERIC("interface SAM { #R m(#ARG); }");
100 String sam_str;
102 SamKind(String sam_str) {
103 this.sam_str = sam_str;
104 }
106 String getSam(TypeKind parameterT, TypeKind returnT) {
107 return sam_str.replaceAll("#ARG",
108 parameterT == TypeKind.VOID ?
109 "" : parameterT.typeStr + " arg")
110 .replaceAll("#R", returnT.typeStr);
111 }
112 }
114 enum TypeKind {
115 VOID("void", ""),
116 STRING("String", "\"hello\""),
117 INTEGER("Integer", "1"),
118 INT("int", "0"),
119 COMPARATOR("java.util.Comparator<String>",
120 "(java.util.Comparator<String>)(a, b) -> a.length()-b.length()"),
121 SAM("SAM2", "null"),
122 GENERIC("T", null);
124 String typeStr;
125 String valStr;
127 TypeKind(String typeStr, String valStr) {
128 this.typeStr = typeStr;
129 this.valStr = valStr;
130 }
131 }
133 enum LambdaKind {
134 EXPRESSION("#VAL"),
135 STATEMENT("{return #VAL;}");
137 String stmt;
139 LambdaKind(String stmt) {
140 this.stmt = stmt;
141 }
142 }
144 enum ParameterKind {
145 EXPLICIT("#TYPE"),
146 IMPLICIT("");
148 String paramTemplate;
150 ParameterKind(String paramTemplate) {
151 this.paramTemplate = paramTemplate;
152 }
153 }
155 enum Keyword {
156 SUPER("super"),
157 EXTENDS("extends"),
158 VOID("");
160 String keyStr;
162 Keyword(String keyStr) {
163 this.keyStr = keyStr;
164 }
165 }
167 enum LambdaBody {
168 //no parameters, return type is one of the TypeKind
169 RETURN_VOID("() -> #RET"),
170 //has parameters, return type is one of the TypeKind
171 RETURN_ARG("(#PK arg) -> #RET");
173 String bodyStr;
175 LambdaBody(String bodyStr) {
176 this.bodyStr = bodyStr;
177 }
179 String getLambdaBody(TypeKind samTargetT, TypeKind parameterT,
180 TypeKind returnT, LambdaKind lk, ParameterKind pk) {
181 String result = bodyStr.replaceAll("#PK", pk.paramTemplate);
183 if(result.contains("#TYPE")) {
184 if (parameterT == TypeKind.GENERIC && this != RETURN_VOID)
185 result = result.replaceAll("#TYPE",
186 samTargetT == null? "": samTargetT.typeStr);
187 else
188 result = result.replaceAll("#TYPE", parameterT.typeStr);
189 }
190 if (this == RETURN_ARG && parameterT == returnT)
191 return result.replaceAll("#RET", lk.stmt.replaceAll("#VAL", "arg"));
192 else {
193 if(returnT != TypeKind.GENERIC)
194 return result.replaceAll("#RET", lk.stmt.replaceAll("#VAL",
195 (returnT==TypeKind.VOID &&
196 lk==LambdaKind.EXPRESSION) ? "{}" : returnT.valStr));
197 else
198 return result.replaceAll("#RET",
199 lk.stmt.replaceAll("#VAL", samTargetT.valStr));
200 }
201 }
202 }
204 enum GenericDeclKind {
205 NON_GENERIC(""),
206 GENERIC_NOBOUND("<T>"),
207 GENERIC_BOUND("<T extends #ExtendedType>");
208 String typeStr;
210 GenericDeclKind(String typeStr) {
211 this.typeStr = typeStr;
212 }
214 String getGenericDeclKind(TypeKind et) {
215 return typeStr.replaceAll("#ExtendedType", et==null? "":et.typeStr);
216 }
217 }
219 boolean checkTypeInference() {
220 if (parameterType == TypeKind.VOID) {
221 if (lambdaBodyType != LambdaBody.RETURN_VOID)
222 return false;
223 }
224 else if (lambdaBodyType != LambdaBody.RETURN_ARG)
225 return false;
226 if ( genericDeclKind == GenericDeclKind.GENERIC_NOBOUND ||
227 genericDeclKind == GenericDeclKind.GENERIC_BOUND ) {
228 if ( parameterType == TypeKind.GENERIC &&
229 parameterKind == ParameterKind.IMPLICIT) //cyclic inference
230 return false;
231 }
232 return true;
233 }
235 String templateStr = "#C\n" +
236 "interface SAM2 {\n" +
237 " SAM m();\n" +
238 "}\n";
239 SourceFile samSourceFile = new SourceFile("Sam.java", templateStr) {
240 public String toString() {
241 return template.replaceAll("#C",
242 samKind.getSam(parameterType, returnType));
243 }
244 };
246 SourceFile clientSourceFile = new SourceFile("Client.java",
247 "class Client { \n" +
248 " #Context\n" +
249 "}") {
250 public String toString() {
251 return template.replaceAll("#Context",
252 context.getContext(samKind, samTargetType, keyword,
253 parameterType, returnType, lambdaKind, parameterKind,
254 genericDeclKind, lambdaBodyType));
255 }
256 };
258 public void run() {
259 outWriter.println("kk:");
260 StringBuilder sb = new StringBuilder("SamKind:");
261 sb.append(samKind).append(" SamTargetType:")
262 .append(samTargetType).append(" ParameterType:").append(parameterType)
263 .append(" ReturnType:").append(returnType).append(" Context:")
264 .append(context).append(" LambdaKind:").append(lambdaKind)
265 .append(" LambdaBodyType:").append(lambdaBodyType)
266 .append(" ParameterKind:").append(parameterKind).append(" Keyword:")
267 .append(keyword);
268 outWriter.println(sb);
269 DiagnosticChecker dc = new DiagnosticChecker();
270 JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), dc,
271 null, null, Arrays.asList(samSourceFile, clientSourceFile));
272 try {
273 ct.analyze();
274 } catch (Throwable t) {
275 processException(t);
276 }
277 if (dc.errorFound == checkTypeInference()) {
278 throw new AssertionError(samSourceFile + "\n\n" +
279 clientSourceFile + "\n" + parameterType + " " + returnType);
280 }
281 }
283 abstract class SourceFile extends SimpleJavaFileObject {
285 protected String template;
287 public SourceFile(String filename, String template) {
288 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
289 this.template = template;
290 }
292 @Override
293 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
294 return toString();
295 }
297 public abstract String toString();
298 }
300 static class DiagnosticChecker
301 implements javax.tools.DiagnosticListener<JavaFileObject> {
303 boolean errorFound = false;
305 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
306 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
307 errorFound = true;
308 }
309 }
310 }
312 SamKind samKind;
313 TypeKind samTargetType;
314 TypeKind parameterType;
315 TypeKind returnType;
316 Context context;
317 LambdaBody lambdaBodyType;
318 LambdaKind lambdaKind;
319 ParameterKind parameterKind;
320 Keyword keyword;
321 GenericDeclKind genericDeclKind;
323 TypeInferenceComboTest(SamKind sk, TypeKind samTargetT, TypeKind parameterT,
324 TypeKind returnT, LambdaBody lb, Context c, LambdaKind lk,
325 ParameterKind pk, Keyword kw, GenericDeclKind gdk) {
326 samKind = sk;
327 samTargetType = samTargetT;
328 parameterType = parameterT;
329 returnType = returnT;
330 context = c;
331 lambdaKind = lk;
332 parameterKind = pk;
333 keyword = kw;
334 lambdaBodyType = lb;
335 genericDeclKind = gdk;
336 }
338 public static void main(String[] args) throws Exception {
339 for(Context ct : Context.values()) {
340 for (TypeKind returnT : TypeKind.values()) {
341 for (TypeKind parameterT : TypeKind.values()) {
342 for(LambdaBody lb : LambdaBody.values()) {
343 for (ParameterKind parameterK : ParameterKind.values()) {
344 for(LambdaKind lambdaK : LambdaKind.values()) {
345 for (SamKind sk : SamKind.values()) {
346 if (sk == SamKind.NON_GENERIC) {
347 generateNonGenericSAM(ct, returnT,
348 parameterT, lb, parameterK,
349 lambdaK, sk);
350 }
351 else if (sk == SamKind.GENERIC) {
352 generateGenericSAM(ct, returnT,
353 parameterT, lb, parameterK,
354 lambdaK, sk);
355 }
356 }
357 }
358 }
359 }
360 }
361 }
362 }
364 checkAfterExec(false);
365 }
367 static void generateNonGenericSAM(Context ct, TypeKind returnT,
368 TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
369 LambdaKind lambdaK, SamKind sk) {
370 if(parameterT != TypeKind.GENERIC && returnT != TypeKind.GENERIC ) {
371 pool.execute(new TypeInferenceComboTest(sk, null, parameterT,
372 returnT, lb, ct, lambdaK, parameterK, null, null));
373 }
374 }
376 static void generateGenericSAM(Context ct, TypeKind returnT,
377 TypeKind parameterT, LambdaBody lb, ParameterKind parameterK,
378 LambdaKind lambdaK, SamKind sk) {
379 for (Keyword kw : Keyword.values()) {
380 for (TypeKind samTargetT : TypeKind.values()) {
381 if(samTargetT != TypeKind.VOID &&
382 samTargetT != TypeKind.INT &&
383 samTargetT != TypeKind.GENERIC &&
384 (parameterT == TypeKind.GENERIC ||
385 returnT == TypeKind.GENERIC)) {
386 if(ct != Context.METHOD_CALL) {
387 pool.execute(
388 new TypeInferenceComboTest(sk, samTargetT, parameterT,
389 returnT, lb, ct, lambdaK, parameterK, kw, null));
390 } else {//Context.METHOD_CALL
391 for (GenericDeclKind gdk :
392 GenericDeclKind.values())
393 pool.execute(
394 new TypeInferenceComboTest(sk, samTargetT,
395 parameterT, returnT, lb, ct, lambdaK,
396 parameterK, kw, gdk));
397 }
398 }
399 }
400 }
401 }
403 }