test/tools/javac/lambda/LambdaParserTest.java

Tue, 14 May 2013 11:11:09 -0700

author
rfield
date
Tue, 14 May 2013 11:11:09 -0700
changeset 1752
c09b7234cded
parent 1520
5c956be64b9e
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8012556: Implement lambda methods on interfaces as static
8006140: Javac NPE compiling Lambda expression on initialization expression of static field in interface
Summary: Lambdas occurring in static contexts or those not needing instance information should be generated into static methods. This has long been the case for classes. However, as a work-around to the lack of support for statics on interfaces, interface lambda methods have been generated into default methods. For lambdas in interface static contexts (fields and static methods) this causes an NPE in javac because there is no 'this'. MethodHandles now support static methods on interfaces. This changeset allows lambda methods to be generated as static interface methods. An existing bug in Hotspot (8013875) is exposed in a test when the "-esa" flag is used. This test and another test that already exposed this bug have been marked with @ignore.
Reviewed-by: mcimadamore

     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 7115050 8003280 8005852 8006694
    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 ../lib
    31  * @build JavacTestingAbstractThreadedTest
    32  * @run main/othervm LambdaParserTest
    33  */
    35 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
    36 // see JDK-8006746
    38 import java.net.URI;
    39 import java.util.Arrays;
    40 import javax.tools.Diagnostic;
    41 import javax.tools.JavaFileObject;
    42 import javax.tools.SimpleJavaFileObject;
    43 import com.sun.source.util.JavacTask;
    45 public class LambdaParserTest
    46     extends JavacTestingAbstractThreadedTest
    47     implements Runnable {
    49     enum LambdaKind {
    50         NILARY_EXPR("()->x"),
    51         NILARY_STMT("()->{ return x; }"),
    52         ONEARY_SHORT_EXPR("#PN->x"),
    53         ONEARY_SHORT_STMT("#PN->{ return x; }"),
    54         ONEARY_EXPR("(#M1 #T1 #PN)->x"),
    55         ONEARY_STMT("(#M1 #T1 #PN)->{ return x; }"),
    56         TWOARY_EXPR("(#M1 #T1 #PN, #M2 #T2 y)->x"),
    57         TWOARY_STMT("(#M1 #T1 #PN, #M2 #T2 y)->{ return x; }");
    59         String lambdaTemplate;
    61         LambdaKind(String lambdaTemplate) {
    62             this.lambdaTemplate = lambdaTemplate;
    63         }
    65         String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
    66                 ModifierKind mk1, ModifierKind mk2, LambdaParameterName pn) {
    67             return lambdaTemplate.replaceAll("#M1", mk1.modifier)
    68                     .replaceAll("#M2", mk2.modifier)
    69                     .replaceAll("#T1", pk1.parameterType)
    70                     .replaceAll("#T2", pk2.parameterType)
    71                     .replaceAll("#PN", pn.nameStr);
    72         }
    74         int arity() {
    75             switch (this) {
    76                 case NILARY_EXPR:
    77                 case NILARY_STMT: return 0;
    78                 case ONEARY_SHORT_EXPR:
    79                 case ONEARY_SHORT_STMT:
    80                 case ONEARY_EXPR:
    81                 case ONEARY_STMT: return 1;
    82                 case TWOARY_EXPR:
    83                 case TWOARY_STMT: return 2;
    84                 default: throw new AssertionError("Invalid lambda kind " + this);
    85             }
    86         }
    88         boolean isShort() {
    89             return this == ONEARY_SHORT_EXPR ||
    90                     this == ONEARY_SHORT_STMT;
    91         }
    92     }
    94     enum LambdaParameterName {
    95         IDENT("x"),
    96         UNDERSCORE("_");
    98         String nameStr;
   100         LambdaParameterName(String nameStr) {
   101             this.nameStr = nameStr;
   102         }
   103     }
   105     enum LambdaParameterKind {
   106         IMPLICIT(""),
   107         EXPLIICT_SIMPLE("A"),
   108         EXPLIICT_SIMPLE_ARR1("A[]"),
   109         EXPLIICT_SIMPLE_ARR2("A[][]"),
   110         EXPLICIT_VARARGS("A..."),
   111         EXPLICIT_GENERIC1("A<X>"),
   112         EXPLICIT_GENERIC2("A<? extends X, ? super Y>"),
   113         EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>..."),
   114         EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]"),
   115         EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]");
   117         String parameterType;
   119         LambdaParameterKind(String parameterType) {
   120             this.parameterType = parameterType;
   121         }
   123         boolean explicit() {
   124             return this != IMPLICIT;
   125         }
   127         boolean isVarargs() {
   128             return this == EXPLICIT_VARARGS ||
   129                     this == EXPLICIT_GENERIC2_VARARGS;
   130         }
   131     }
   133     enum ModifierKind {
   134         NONE(""),
   135         FINAL("final"),
   136         PUBLIC("public");
   138         String modifier;
   140         ModifierKind(String modifier) {
   141             this.modifier = modifier;
   142         }
   144         boolean compatibleWith(LambdaParameterKind pk) {
   145             switch (this) {
   146                 case PUBLIC: return false;
   147                 case FINAL: return pk != LambdaParameterKind.IMPLICIT;
   148                 case NONE: return true;
   149                 default: throw new AssertionError("Invalid modifier kind " + this);
   150             }
   151         }
   152     }
   154     enum ExprKind {
   155         NONE("#L#S"),
   156         SINGLE_PAREN1("(#L#S)"),
   157         SINGLE_PAREN2("(#L)#S"),
   158         DOUBLE_PAREN1("((#L#S))"),
   159         DOUBLE_PAREN2("((#L)#S)"),
   160         DOUBLE_PAREN3("((#L))#S");
   162         String expressionTemplate;
   164         ExprKind(String expressionTemplate) {
   165             this.expressionTemplate = expressionTemplate;
   166         }
   168         String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
   169                 ModifierKind mk1, ModifierKind mk2, LambdaKind lk, LambdaParameterName pn, SubExprKind sk) {
   170             return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2, pn))
   171                     .replaceAll("#S", sk.subExpression);
   172         }
   173     }
   175     enum SubExprKind {
   176         NONE(""),
   177         SELECT_FIELD(".f"),
   178         SELECT_METHOD(".f()"),
   179         SELECT_NEW(".new Foo()"),
   180         POSTINC("++"),
   181         POSTDEC("--");
   183         String subExpression;
   185         SubExprKind(String subExpression) {
   186             this.subExpression = subExpression;
   187         }
   188     }
   190     public static void main(String... args) throws Exception {
   191         for (LambdaKind lk : LambdaKind.values()) {
   192             for (LambdaParameterName pn : LambdaParameterName.values()) {
   193                 for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
   194                     if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT)
   195                         continue;
   196                     for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
   197                         if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT)
   198                             continue;
   199                         for (ModifierKind mk1 : ModifierKind.values()) {
   200                             if (mk1 != ModifierKind.NONE && lk.isShort())
   201                                 continue;
   202                             if (lk.arity() < 1 && mk1 != ModifierKind.NONE)
   203                                 continue;
   204                             for (ModifierKind mk2 : ModifierKind.values()) {
   205                                 if (lk.arity() < 2 && mk2 != ModifierKind.NONE)
   206                                     continue;
   207                                 for (SubExprKind sk : SubExprKind.values()) {
   208                                     for (ExprKind ek : ExprKind.values()) {
   209                                         pool.execute(
   210                                             new LambdaParserTest(pk1, pk2, mk1,
   211                                                                  mk2, lk, sk, ek, pn));
   212                                     }
   213                                 }
   214                             }
   215                         }
   216                     }
   217                 }
   218             }
   219         }
   221         checkAfterExec();
   222     }
   224     LambdaParameterKind pk1;
   225     LambdaParameterKind pk2;
   226     ModifierKind mk1;
   227     ModifierKind mk2;
   228     LambdaKind lk;
   229     LambdaParameterName pn;
   230     SubExprKind sk;
   231     ExprKind ek;
   232     JavaSource source;
   233     DiagnosticChecker diagChecker;
   235     LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2,
   236             ModifierKind mk1, ModifierKind mk2, LambdaKind lk,
   237             SubExprKind sk, ExprKind ek, LambdaParameterName pn) {
   238         this.pk1 = pk1;
   239         this.pk2 = pk2;
   240         this.mk1 = mk1;
   241         this.mk2 = mk2;
   242         this.lk = lk;
   243         this.pn = pn;
   244         this.sk = sk;
   245         this.ek = ek;
   246         this.source = new JavaSource();
   247         this.diagChecker = new DiagnosticChecker();
   248     }
   250     class JavaSource extends SimpleJavaFileObject {
   252         String template = "class Test {\n" +
   253                           "   SAM s = #E;\n" +
   254                           "}";
   256         String source;
   258         public JavaSource() {
   259             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   260             source = template.replaceAll("#E",
   261                     ek.expressionString(pk1, pk2, mk1, mk2, lk, pn, sk));
   262         }
   264         @Override
   265         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   266             return source;
   267         }
   268     }
   270     public void run() {
   271         JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
   272                 null, null, Arrays.asList(source));
   273         try {
   274             ct.parse();
   275         } catch (Throwable ex) {
   276             processException(ex);
   277             return;
   278         }
   279         check();
   280     }
   282     void check() {
   283         checkCount.incrementAndGet();
   285         boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
   286                 (lk.arity() > 1 && !mk2.compatibleWith(pk2));
   288         if (lk.arity() == 2 &&
   289                 (pk1.explicit() != pk2.explicit() ||
   290                 pk1.isVarargs())) {
   291             errorExpected = true;
   292         }
   294         errorExpected |= pn == LambdaParameterName.UNDERSCORE &&
   295                 lk.arity() > 0;
   297         if (errorExpected != diagChecker.errorFound) {
   298             throw new Error("invalid diagnostics for source:\n" +
   299                 source.getCharContent(true) +
   300                 "\nFound error: " + diagChecker.errorFound +
   301                 "\nExpected error: " + errorExpected);
   302         }
   303     }
   305     static class DiagnosticChecker
   306         implements javax.tools.DiagnosticListener<JavaFileObject> {
   308         boolean errorFound;
   310         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   311             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   312                 errorFound = true;
   313             }
   314         }
   315     }
   317 }

mercurial