1 /* 2 * Copyright (c) 2011, 2018, 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 7115050 8003280 8005852 8006694 8129962 27 * @summary Add lambda tests 28 * Add parser support for lambda expressions 29 * temporarily workaround combo tests are causing time out in several platforms 30 * @library /tools/javac/lib 31 * @modules jdk.compiler/com.sun.tools.javac.api 32 * jdk.compiler/com.sun.tools.javac.code 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 40 */ 41 42 import java.io.IOException; 43 import java.util.Arrays; 44 45 import combo.ComboInstance; 46 import combo.ComboParameter; 47 import combo.ComboTask.Result; 48 import combo.ComboTestHelper; 49 50 public class LambdaParserTest extends ComboInstance<LambdaParserTest> { 51 52 enum LambdaKind implements ComboParameter { 53 NILARY_EXPR("()->x"), 54 NILARY_STMT("()->{ return x; }"), 55 ONEARY_SHORT_EXPR("#{NAME}->x"), 56 ONEARY_SHORT_STMT("#{NAME}->{ return x; }"), 57 ONEARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME})->x"), 58 ONEARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME})->{ return x; }"), 59 TWOARY_EXPR("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->x"), 60 TWOARY_STMT("(#{MOD[0]} #{TYPE[0]} #{NAME}, #{MOD[1]} #{TYPE[1]} y)->{ return x; }"); 61 62 String lambdaTemplate; 63 LambdaKind(String lambdaTemplate)64 LambdaKind(String lambdaTemplate) { 65 this.lambdaTemplate = lambdaTemplate; 66 } 67 68 @Override expand(String optParameter)69 public String expand(String optParameter) { 70 return lambdaTemplate; 71 } 72 arity()73 int arity() { 74 switch (this) { 75 case NILARY_EXPR: 76 case NILARY_STMT: return 0; 77 case ONEARY_SHORT_EXPR: 78 case ONEARY_SHORT_STMT: 79 case ONEARY_EXPR: 80 case ONEARY_STMT: return 1; 81 case TWOARY_EXPR: 82 case TWOARY_STMT: return 2; 83 default: throw new AssertionError("Invalid lambda kind " + this); 84 } 85 } 86 isShort()87 boolean isShort() { 88 return this == ONEARY_SHORT_EXPR || 89 this == ONEARY_SHORT_STMT; 90 } 91 } 92 93 enum LambdaParameterName implements ComboParameter { 94 IDENT("x"), 95 UNDERSCORE("_"); 96 97 String nameStr; 98 LambdaParameterName(String nameStr)99 LambdaParameterName(String nameStr) { 100 this.nameStr = nameStr; 101 } 102 103 @Override expand(String optParameter)104 public String expand(String optParameter) { 105 return nameStr; 106 } 107 } 108 109 enum SourceKind { 110 SOURCE_9("9"), 111 SOURCE_10("10"); 112 113 String sourceNumber; 114 SourceKind(String sourceNumber)115 SourceKind(String sourceNumber) { 116 this.sourceNumber = sourceNumber; 117 } 118 } 119 120 enum LambdaParameterKind implements ComboParameter { 121 122 IMPLICIT_1("", ExplicitKind.IMPLICIT), 123 IMPLICIT_2("var", ExplicitKind.IMPLICIT_VAR), 124 EXPLIICT_SIMPLE("A", ExplicitKind.EXPLICIT), 125 EXPLIICT_SIMPLE_ARR1("A[]", ExplicitKind.EXPLICIT), 126 EXPLIICT_SIMPLE_ARR2("A[][]", ExplicitKind.EXPLICIT), 127 EXPLICIT_VARARGS("A...", ExplicitKind.EXPLICIT), 128 EXPLICIT_GENERIC1("A<X>", ExplicitKind.EXPLICIT), 129 EXPLICIT_GENERIC2("A<? extends X, ? super Y>", ExplicitKind.EXPLICIT), 130 EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>...", ExplicitKind.EXPLICIT), 131 EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]", ExplicitKind.EXPLICIT), 132 EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]", ExplicitKind.EXPLICIT); 133 134 enum ExplicitKind { 135 IMPLICIT, 136 IMPLICIT_VAR, 137 EXPLICIT; 138 } 139 140 String parameterType; 141 ExplicitKind explicitKind; 142 143 LambdaParameterKind(String parameterType, ExplicitKind ekind)144 LambdaParameterKind(String parameterType, ExplicitKind ekind) { 145 this.parameterType = parameterType; 146 this.explicitKind = ekind; 147 } 148 isVarargs()149 boolean isVarargs() { 150 return this == EXPLICIT_VARARGS || 151 this == EXPLICIT_GENERIC2_VARARGS; 152 } 153 154 @Override expand(String optParameter)155 public String expand(String optParameter) { 156 return parameterType; 157 } 158 explicitKind(SourceKind sk)159 ExplicitKind explicitKind(SourceKind sk) { 160 switch (explicitKind) { 161 case IMPLICIT_VAR: 162 return (sk == SourceKind.SOURCE_9) ? 163 ExplicitKind.EXPLICIT : ExplicitKind.IMPLICIT_VAR; 164 default: 165 return explicitKind; 166 } 167 } 168 } 169 170 enum ModifierKind implements ComboParameter { 171 NONE(""), 172 FINAL("final"), 173 PUBLIC("public"), 174 ANNO("@A"); 175 176 String modifier; 177 ModifierKind(String modifier)178 ModifierKind(String modifier) { 179 this.modifier = modifier; 180 } 181 compatibleWith(LambdaParameterKind pk)182 boolean compatibleWith(LambdaParameterKind pk) { 183 switch (this) { 184 case PUBLIC: return false; 185 case ANNO: 186 case FINAL: return pk != LambdaParameterKind.IMPLICIT_1; 187 case NONE: return true; 188 default: throw new AssertionError("Invalid modifier kind " + this); 189 } 190 } 191 192 @Override expand(String optParameter)193 public String expand(String optParameter) { 194 return modifier; 195 } 196 } 197 198 enum ExprKind implements ComboParameter { 199 NONE("#{LAMBDA}#{SUBEXPR}"), 200 SINGLE_PAREN1("(#{LAMBDA}#{SUBEXPR})"), 201 SINGLE_PAREN2("(#{LAMBDA})#{SUBEXPR}"), 202 DOUBLE_PAREN1("((#{LAMBDA}#{SUBEXPR}))"), 203 DOUBLE_PAREN2("((#{LAMBDA})#{SUBEXPR})"), 204 DOUBLE_PAREN3("((#{LAMBDA}))#{SUBEXPR}"); 205 206 String expressionTemplate; 207 ExprKind(String expressionTemplate)208 ExprKind(String expressionTemplate) { 209 this.expressionTemplate = expressionTemplate; 210 } 211 212 @Override expand(String optParameter)213 public String expand(String optParameter) { 214 return expressionTemplate; 215 } 216 } 217 218 enum SubExprKind implements ComboParameter { 219 NONE(""), 220 SELECT_FIELD(".f"), 221 SELECT_METHOD(".f()"), 222 SELECT_NEW(".new Foo()"), 223 POSTINC("++"), 224 POSTDEC("--"); 225 226 String subExpression; 227 SubExprKind(String subExpression)228 SubExprKind(String subExpression) { 229 this.subExpression = subExpression; 230 } 231 232 @Override expand(String optParameter)233 public String expand(String optParameter) { 234 return subExpression; 235 } 236 } 237 main(String... args)238 public static void main(String... args) throws Exception { 239 new ComboTestHelper<LambdaParserTest>() 240 .withFilter(LambdaParserTest::redundantTestFilter) 241 .withFilter(LambdaParserTest::badImplicitFilter) 242 .withDimension("SOURCE", (x, sk) -> x.sk = sk, SourceKind.values()) 243 .withDimension("LAMBDA", (x, lk) -> x.lk = lk, LambdaKind.values()) 244 .withDimension("NAME", (x, name) -> x.pn = name, LambdaParameterName.values()) 245 .withArrayDimension("TYPE", (x, type, idx) -> x.pks[idx] = type, 2, LambdaParameterKind.values()) 246 .withArrayDimension("MOD", (x, mod, idx) -> x.mks[idx] = mod, 2, ModifierKind.values()) 247 .withDimension("EXPR", ExprKind.values()) 248 .withDimension("SUBEXPR", SubExprKind.values()) 249 .run(LambdaParserTest::new); 250 } 251 252 LambdaParameterKind[] pks = new LambdaParameterKind[2]; 253 ModifierKind[] mks = new ModifierKind[2]; 254 LambdaKind lk; 255 LambdaParameterName pn; 256 SourceKind sk; 257 badImplicitFilter()258 boolean badImplicitFilter() { 259 return !(mks[0] != ModifierKind.NONE && lk.isShort()); 260 } 261 redundantTestFilter()262 boolean redundantTestFilter() { 263 for (int i = lk.arity(); i < mks.length ; i++) { 264 if (mks[i].ordinal() != 0) { 265 return false; 266 } 267 } 268 for (int i = lk.arity(); i < pks.length ; i++) { 269 if (pks[i].ordinal() != 0) { 270 return false; 271 } 272 } 273 return true; 274 } 275 276 String template = "@interface A { }\n" + 277 "class Test {\n" + 278 " SAM s = #{EXPR};\n" + 279 "}"; 280 281 @Override doWork()282 public void doWork() throws IOException { 283 newCompilationTask() 284 .withOptions(Arrays.asList("-source", sk.sourceNumber)) 285 .withSourceFromTemplate(template) 286 .parse(this::check); 287 } 288 check(Result<?> res)289 void check(Result<?> res) { 290 boolean errorExpected = (lk.arity() > 0 && !mks[0].compatibleWith(pks[0])) || 291 (lk.arity() > 1 && !mks[1].compatibleWith(pks[1])); 292 293 if (lk.arity() == 2 && 294 (pks[0].explicitKind(sk) != pks[1].explicitKind(sk) || 295 pks[0].isVarargs())) { 296 errorExpected = true; 297 } 298 299 errorExpected |= pn == LambdaParameterName.UNDERSCORE && 300 lk.arity() > 0; 301 302 if (errorExpected != res.hasErrors()) { 303 fail("invalid diagnostics for source:\n" + 304 res.compilationInfo() + 305 "\nFound error: " + res.hasErrors() + 306 "\nExpected error: " + errorExpected); 307 } 308 } 309 } 310