langtools/test/tools/javac/lambda/LambdaParserTest.java
changeset 32454 b0ac04e0fefe
parent 30730 d3ce7619db2c
equal deleted inserted replaced
32453:8eebd1f0b8ea 32454:b0ac04e0fefe
    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:
    90             return this == ONEARY_SHORT_EXPR ||
    87             return this == ONEARY_SHORT_EXPR ||
    91                     this == ONEARY_SHORT_STMT;
    88                     this == ONEARY_SHORT_STMT;
    92         }
    89         }
    93     }
    90     }
    94 
    91 
    95     enum LambdaParameterName {
    92     enum LambdaParameterName implements ComboParameter {
    96         IDENT("x"),
    93         IDENT("x"),
    97         UNDERSCORE("_");
    94         UNDERSCORE("_");
    98 
    95 
    99         String nameStr;
    96         String nameStr;
   100 
    97 
   101         LambdaParameterName(String nameStr) {
    98         LambdaParameterName(String nameStr) {
   102             this.nameStr = nameStr;
    99             this.nameStr = nameStr;
   103         }
   100         }
   104     }
   101 
   105 
   102         @Override
   106     enum LambdaParameterKind {
   103         public String expand(String optParameter) {
       
   104             return nameStr;
       
   105         }
       
   106     }
       
   107 
       
   108     enum LambdaParameterKind implements ComboParameter {
   107         IMPLICIT(""),
   109         IMPLICIT(""),
   108         EXPLIICT_SIMPLE("A"),
   110         EXPLIICT_SIMPLE("A"),
   109         EXPLIICT_SIMPLE_ARR1("A[]"),
   111         EXPLIICT_SIMPLE_ARR1("A[]"),
   110         EXPLIICT_SIMPLE_ARR2("A[][]"),
   112         EXPLIICT_SIMPLE_ARR2("A[][]"),
   111         EXPLICIT_VARARGS("A..."),
   113         EXPLICIT_VARARGS("A..."),
   127 
   129 
   128         boolean isVarargs() {
   130         boolean isVarargs() {
   129             return this == EXPLICIT_VARARGS ||
   131             return this == EXPLICIT_VARARGS ||
   130                     this == EXPLICIT_GENERIC2_VARARGS;
   132                     this == EXPLICIT_GENERIC2_VARARGS;
   131         }
   133         }
   132     }
   134 
   133 
   135         @Override
   134     enum ModifierKind {
   136         public String expand(String optParameter) {
       
   137             return parameterType;
       
   138         }
       
   139     }
       
   140 
       
   141     enum ModifierKind implements ComboParameter {
   135         NONE(""),
   142         NONE(""),
   136         FINAL("final"),
   143         FINAL("final"),
   137         PUBLIC("public");
   144         PUBLIC("public");
   138 
   145 
   139         String modifier;
   146         String modifier;
   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 }