21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 7115050 8003280 8005852 8006694 |
26 * @bug 7115050 8003280 8005852 8006694 8129962 |
27 * @summary Add lambda tests |
27 * @summary Add lambda tests |
28 * Add parser support for lambda expressions |
28 * Add parser support for lambda expressions |
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 LambdaParserTest |
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 |
|
39 * @run main LambdaParserTest |
34 */ |
40 */ |
35 |
41 |
36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) |
42 import java.io.IOException; |
37 // see JDK-8006746 |
43 |
38 |
44 import combo.ComboInstance; |
39 import java.net.URI; |
45 import combo.ComboParameter; |
40 import java.util.Arrays; |
46 import combo.ComboTask.Result; |
41 import javax.tools.Diagnostic; |
47 import combo.ComboTestHelper; |
42 import javax.tools.JavaFileObject; |
48 |
43 import javax.tools.SimpleJavaFileObject; |
49 public class LambdaParserTest extends ComboInstance<LambdaParserTest> { |
44 import com.sun.source.util.JavacTask; |
50 |
45 |
51 enum LambdaKind implements ComboParameter { |
46 public class LambdaParserTest |
|
47 extends JavacTestingAbstractThreadedTest |
|
48 implements Runnable { |
|
49 |
|
50 enum LambdaKind { |
|
51 NILARY_EXPR("()->x"), |
52 NILARY_EXPR("()->x"), |
52 NILARY_STMT("()->{ return x; }"), |
53 NILARY_STMT("()->{ return x; }"), |
53 ONEARY_SHORT_EXPR("#PN->x"), |
54 ONEARY_SHORT_EXPR("#{NAME}->x"), |
54 ONEARY_SHORT_STMT("#PN->{ return x; }"), |
55 ONEARY_SHORT_STMT("#{NAME}->{ return x; }"), |
55 ONEARY_EXPR("(#M1 #T1 #PN)->x"), |
56 ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"), |
56 ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"), |
57 ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"), |
57 TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"), |
58 TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"), |
58 TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }"); |
59 TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }"); |
59 |
60 |
60 String lambdaTemplate; |
61 String lambdaTemplate; |
61 |
62 |
62 LambdaKind(String lambdaTemplate) { |
63 LambdaKind(String lambdaTemplate) { |
63 this.lambdaTemplate = lambdaTemplate; |
64 this.lambdaTemplate = lambdaTemplate; |
64 } |
65 } |
65 |
66 |
66 String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2, |
67 @Override |
67 ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) { |
68 public String expand(String optParameter) { |
68 return lambdaTemplate.replaceAll("#M1", mk1.modifier) |
69 return lambdaTemplate; |
69 .replaceAll("#M2", mk2.modifier) |
|
70 .replaceAll("#T1", pk1.parameterType) |
|
71 .replaceAll("#T2", pk2.parameterType) |
|
72 .replaceAll("#PN", pn.nameStr); |
|
73 } |
70 } |
74 |
71 |
75 int arity() { |
72 int arity() { |
76 switch (this) { |
73 switch (this) { |
77 case NILARY_EXPR: |
74 case NILARY_EXPR: |
148 case FINAL: return pk != LambdaParameterKind.IMPLICIT; |
155 case FINAL: return pk != LambdaParameterKind.IMPLICIT; |
149 case NONE: return true; |
156 case NONE: return true; |
150 default: throw new AssertionError("Invalid modifier kind " + this); |
157 default: throw new AssertionError("Invalid modifier kind " + this); |
151 } |
158 } |
152 } |
159 } |
153 } |
160 |
154 |
161 @Override |
155 enum ExprKind { |
162 public String expand(String optParameter) { |
156 NONE("#L#S"), |
163 return modifier; |
157 SINGLE_PAREN1("(#L#S)"), |
164 } |
158 SINGLE_PAREN2("(#L)#S"), |
165 } |
159 DOUBLE_PAREN1("((#L#S))"), |
166 |
160 DOUBLE_PAREN2("((#L)#S)"), |
167 enum ExprKind implements ComboParameter { |
161 DOUBLE_PAREN3("((#L))#S"); |
168 NONE("#{LAMBDA}#{SUBEXPR}"), |
|
169 SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"), |
|
170 SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"), |
|
171 DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"), |
|
172 DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"), |
|
173 DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}"); |
162 |
174 |
163 String expressionTemplate; |
175 String expressionTemplate; |
164 |
176 |
165 ExprKind(String expressionTemplate) { |
177 ExprKind(String expressionTemplate) { |
166 this.expressionTemplate = expressionTemplate; |
178 this.expressionTemplate = expressionTemplate; |
167 } |
179 } |
168 |
180 |
169 String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2, |
181 @Override |
170 ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) { |
182 public String expand(String optParameter) { |
171 return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn)) |
183 return expressionTemplate; |
172 .replaceAll("#S", sk.subExpression); |
184 } |
173 } |
185 } |
174 } |
186 |
175 |
187 enum SubExprKind implements ComboParameter { |
176 enum SubExprKind { |
|
177 NONE(""), |
188 NONE(""), |
178 SELECT_FIELD(".f"), |
189 SELECT_FIELD(".f"), |
179 SELECT_METHOD(".f()"), |
190 SELECT_METHOD(".f()"), |
180 SELECT_NEW(".new Foo()"), |
191 SELECT_NEW(".new Foo()"), |
181 POSTINC("++"), |
192 POSTINC("++"), |
184 String subExpression; |
195 String subExpression; |
185 |
196 |
186 SubExprKind(String subExpression) { |
197 SubExprKind(String subExpression) { |
187 this.subExpression = subExpression; |
198 this.subExpression = subExpression; |
188 } |
199 } |
|
200 |
|
201 @Override |
|
202 public String expand(String optParameter) { |
|
203 return subExpression; |
|
204 } |
189 } |
205 } |
190 |
206 |
191 public static void main(String... args) throws Exception { |
207 public static void main(String... args) throws Exception { |
192 for (LambdaKind lk : LambdaKind.values()) { |
208 new ComboTestHelper<LambdaParserTest>() |
193 for (LambdaParameterName pn : LambdaParameterName.values()) { |
209 .withFilter(LambdaParserTest::redundantTestFilter) |
194 for (LambdaParameterKind pk1 : LambdaParameterKind.values()) { |
210 .withFilter(LambdaParserTest::badImplicitFilter) |
195 if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT) |
211 .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values()) |
196 continue; |
212 .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values()) |
197 for (LambdaParameterKind pk2 : LambdaParameterKind.values()) { |
213 .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values()) |
198 if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT) |
214 .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values()) |
199 continue; |
215 .withDimension("EXPR", ExprKind.values()) |
200 for (ModifierKind mk1 : ModifierKind.values()) { |
216 .withDimension("SUBEXPR", SubExprKind.values()) |
201 if (mk1 != ModifierKind.NONE && lk.isShort()) |
217 .run(LambdaParserTest::new); |
202 continue; |
218 } |
203 if (lk.arity() < 1 && mk1 != ModifierKind.NONE) |
219 |
204 continue; |
220 LambdaParameterKind[] pks = new LambdaParameterKind[2]; |
205 for (ModifierKind mk2 : ModifierKind.values()) { |
221 ModifierKind[] mks = new ModifierKind[2]; |
206 if (lk.arity() < 2 && mk2 != ModifierKind.NONE) |
|
207 continue; |
|
208 for (SubExprKind sk : SubExprKind.values()) { |
|
209 for (ExprKind ek : ExprKind.values()) { |
|
210 pool.execute( |
|
211 new LambdaParserTest(pk1, pk2, mk1, |
|
212 mk2, lk, sk, ek, pn)); |
|
213 } |
|
214 } |
|
215 } |
|
216 } |
|
217 } |
|
218 } |
|
219 } |
|
220 } |
|
221 |
|
222 checkAfterExec(); |
|
223 } |
|
224 |
|
225 LambdaParameterKind pk1; |
|
226 LambdaParameterKind pk2; |
|
227 ModifierKind mk1; |
|
228 ModifierKind mk2; |
|
229 LambdaKind lk; |
222 LambdaKind lk; |
230 LambdaParameterName pn; |
223 LambdaParameterName pn; |
231 SubExprKind sk; |
224 |
232 ExprKind ek; |
225 boolean badImplicitFilter() { |
233 JavaSource source; |
226 return !(mks[0] != ModifierKind.NONE && lk.isShort()); |
234 DiagnosticChecker diagChecker; |
227 } |
235 |
228 |
236 LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2, |
229 boolean redundantTestFilter() { |
237 ModifierKind mk1, ModifierKind mk2, LambdaKind lk, |
230 for (int i = lk.arity(); i < mks.length ; i++) { |
238 SubExprKind sk, ExprKind ek, LambdaParameterName pn) { |
231 if (mks[i].ordinal() != 0) { |
239 this.pk1 = pk1; |
232 return false; |
240 this.pk2 = pk2; |
233 } |
241 this.mk1 = mk1; |
234 } |
242 this.mk2 = mk2; |
235 for (int i = lk.arity(); i < pks.length ; i++) { |
243 this.lk = lk; |
236 if (pks[i].ordinal() != 0) { |
244 this.pn = pn; |
237 return false; |
245 this.sk = sk; |
238 } |
246 this.ek = ek; |
239 } |
247 this.source = new JavaSource(); |
240 return true; |
248 this.diagChecker = new DiagnosticChecker(); |
241 } |
249 } |
242 |
250 |
243 String template = "class Test {\n" + |
251 class JavaSource extends SimpleJavaFileObject { |
244 " SAM s = #{EXPR};\n" + |
252 |
245 "}"; |
253 String template = "class Test {\n" + |
246 |
254 " SAM s = #E;\n" + |
247 @Override |
255 "}"; |
248 public void doWork() throws IOException { |
256 |
249 check(newCompilationTask() |
257 String source; |
250 .withSourceFromTemplate(template) |
258 |
251 .parse()); |
259 public JavaSource() { |
252 } |
260 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
253 |
261 source = template.replaceAll("#E", |
254 void check(Result<?> res) { |
262 ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk)); |
255 boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) || |
263 } |
256 (lk.arity() > 1 && !mks[1].compatibleWith(pks[1])); |
264 |
|
265 @Override |
|
266 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
|
267 return source; |
|
268 } |
|
269 } |
|
270 |
|
271 public void run() { |
|
272 JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, |
|
273 null, null, Arrays.asList(source)); |
|
274 try { |
|
275 ct.parse(); |
|
276 } catch (Throwable ex) { |
|
277 processException(ex); |
|
278 return; |
|
279 } |
|
280 check(); |
|
281 } |
|
282 |
|
283 void check() { |
|
284 checkCount.incrementAndGet(); |
|
285 |
|
286 boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) || |
|
287 (lk.arity() > 1 && !mk2.compatibleWith(pk2)); |
|
288 |
257 |
289 if (lk.arity() == 2 && |
258 if (lk.arity() == 2 && |
290 (pk1.explicit() != pk2.explicit() || |
259 (pks[0].explicit() != pks[1].explicit() || |
291 pk1.isVarargs())) { |
260 pks[0].isVarargs())) { |
292 errorExpected = true; |
261 errorExpected = true; |
293 } |
262 } |
294 |
263 |
295 errorExpected |= pn == LambdaParameterName.UNDERSCORE && |
264 errorExpected |= pn == LambdaParameterName.UNDERSCORE && |
296 lk.arity() > 0; |
265 lk.arity() > 0; |
297 |
266 |
298 if (errorExpected != diagChecker.errorFound) { |
267 if (errorExpected != res.hasErrors()) { |
299 throw new Error("invalid diagnostics for source:\n" + |
268 fail("invalid diagnostics for source:\n" + |
300 source.getCharContent(true) + |
269 res.compilationInfo() + |
301 "\nFound error: " + diagChecker.errorFound + |
270 "\nFound error: " + res.hasErrors() + |
302 "\nExpected error: " + errorExpected); |
271 "\nExpected error: " + errorExpected); |
303 } |
272 } |
304 } |
273 } |
305 |
|
306 static class DiagnosticChecker |
|
307 implements javax.tools.DiagnosticListener<JavaFileObject> { |
|
308 |
|
309 boolean errorFound; |
|
310 |
|
311 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
|
312 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { |
|
313 errorFound = true; |
|
314 } |
|
315 } |
|
316 } |
|
317 |
|
318 } |
274 } |