test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.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 2000
4a6acc42c3a1
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) 2012, 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 8006694
    27  * @summary Add lambda tests
    28  *  Automatic test for checking correctness of structural most specific test routine
    29  *  temporarily workaround combo tests are causing time out in several platforms
    30  * @library ../../lib
    31  * @build JavacTestingAbstractThreadedTest
    32  * @run main/othervm/timeout=600 StructuralMostSpecificTest
    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;
    44 import com.sun.tools.javac.api.ClientCodeWrapper;
    45 import com.sun.tools.javac.util.JCDiagnostic;
    47 public class StructuralMostSpecificTest
    48     extends JavacTestingAbstractThreadedTest
    49     implements Runnable {
    51     enum RetTypeKind {
    52         SHORT("short"),
    53         INT("int"),
    54         OBJECT("Object"),
    55         INTEGER("Integer"),
    56         VOID("void"),
    57         J_L_VOID("Void");
    59         String retTypeStr;
    61         RetTypeKind(String retTypeStr) {
    62             this.retTypeStr = retTypeStr;
    63         }
    65         boolean moreSpecificThan(RetTypeKind rk) {
    66             return moreSpecificThan[this.ordinal()][rk.ordinal()];
    67         }
    69         static boolean[][] moreSpecificThan = {
    70                 //              SHORT |  INT  | OBJECT | INTEGER | VOID  | J_L_VOID
    71                 /* SHORT */   { true  , true  , true   , false   , false , false },
    72                 /* INT */     { false , true  , true   , true    , false , false },
    73                 /* OBJECT */  { false , false , true   , false   , false , false },
    74                 /* INTEGER */ { false , false , true   , true    , false , false },
    75                 /* VOID */    { false , false , false  , false   , true  , true  },
    76                 /* J_L_VOID */{ false , false , true   , false   , false , true  } };
    77     }
    79     enum ArgTypeKind {
    80         SHORT("short"),
    81         INT("int"),
    82         BOOLEAN("boolean"),
    83         OBJECT("Object"),
    84         INTEGER("Integer"),
    85         DOUBLE("Double");
    87         String argTypeStr;
    89         ArgTypeKind(String typeStr) {
    90             this.argTypeStr = typeStr;
    91         }
    92     }
    94     enum ExceptionKind {
    95         NONE(""),
    96         EXCEPTION("throws Exception"),
    97         SQL_EXCEPTION("throws java.sql.SQLException"),
    98         IO_EXCEPTION("throws java.io.IOException");
   100         String exceptionStr;
   102         ExceptionKind(String exceptionStr) {
   103             this.exceptionStr = exceptionStr;
   104         }
   105     }
   107     enum LambdaReturnKind {
   108         VOID("return;"),
   109         SHORT("return (short)0;"),
   110         INT("return 0;"),
   111         INTEGER("return (Integer)null;"),
   112         NULL("return null;");
   114         String retStr;
   116         LambdaReturnKind(String retStr) {
   117             this.retStr = retStr;
   118         }
   120         boolean compatibleWith(RetTypeKind rk) {
   121             return compatibleWith[rk.ordinal()][ordinal()];
   122         }
   124         static boolean[][] compatibleWith = {
   125                 //              VOID  | SHORT | INT     | INTEGER | NULL
   126                 /* SHORT */   { false , true  , false   , false   , false },
   127                 /* INT */     { false , true  , true    , true    , false },
   128                 /* OBJECT */  { false , true  , true    , true    , true  },
   129                 /* INTEGER */ { false , false , true    , true    , true  },
   130                 /* VOID */    { true  , false , false   , false   , false },
   131                 /* J_L_VOID */{ false , false , false   , false   , true  } };
   133         boolean needsConversion(RetTypeKind rk) {
   134             return needsConversion[rk.ordinal()][ordinal()];
   135         }
   137         static boolean[][] needsConversion = {
   138                 //              VOID  | SHORT | INT     | INTEGER | NULL
   139                 /* SHORT */   { false , false , false   , false   , false },
   140                 /* INT */     { false , false , false   , true    , false },
   141                 /* OBJECT */  { false , true  , true    , false   , false },
   142                 /* INTEGER */ { false , false , true    , false   , false },
   143                 /* VOID */    { false , false , false   , false   , false },
   144                 /* J_L_VOID */{ true  , false , false   , false   , false } };
   145     }
   147     public static void main(String... args) throws Exception {
   148         for (LambdaReturnKind lrk : LambdaReturnKind.values()) {
   149             for (RetTypeKind rk1 : RetTypeKind.values()) {
   150                 for (RetTypeKind rk2 : RetTypeKind.values()) {
   151                     for (ExceptionKind ek1 : ExceptionKind.values()) {
   152                         for (ExceptionKind ek2 : ExceptionKind.values()) {
   153                             for (ArgTypeKind ak11 : ArgTypeKind.values()) {
   154                                 for (ArgTypeKind ak12 : ArgTypeKind.values()) {
   155                                     pool.execute(
   156                                         new StructuralMostSpecificTest(lrk, rk1,
   157                                             rk2, ek1, ek2, ak11, ak12));
   158                                 }
   159                             }
   160                         }
   161                     }
   162                 }
   163             }
   164         }
   166         checkAfterExec();
   167     }
   169     LambdaReturnKind lrk;
   170     RetTypeKind rt1, rt2;
   171     ArgTypeKind ak1, ak2;
   172     ExceptionKind ek1, ek2;
   173     JavaSource source;
   174     DiagnosticChecker diagChecker;
   176     StructuralMostSpecificTest(LambdaReturnKind lrk, RetTypeKind rt1, RetTypeKind rt2,
   177             ExceptionKind ek1, ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) {
   178         this.lrk = lrk;
   179         this.rt1 = rt1;
   180         this.rt2 = rt2;
   181         this.ek1 = ek1;
   182         this.ek2 = ek2;
   183         this.ak1 = ak1;
   184         this.ak2 = ak2;
   185         this.source = new JavaSource();
   186         this.diagChecker = new DiagnosticChecker();
   187     }
   189     class JavaSource extends SimpleJavaFileObject {
   191         String template = "interface SAM1 {\n" +
   192                           "   #R1 m(#A1 a1) #E1;\n" +
   193                           "}\n" +
   194                           "interface SAM2 {\n" +
   195                           "   #R2 m(#A2 a1) #E2;\n" +
   196                           "}\n" +
   197                           "class Test {\n" +
   198                           "   void m(SAM1 s) { }\n" +
   199                           "   void m(SAM2 s) { }\n" +
   200                           "   { m(x->{ #LR }); }\n" +
   201                           "}\n";
   203         String source;
   205         public JavaSource() {
   206             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   207             source = template.replaceAll("#LR", lrk.retStr)
   208                     .replaceAll("#R1", rt1.retTypeStr)
   209                     .replaceAll("#R2", rt2.retTypeStr)
   210                     .replaceAll("#A1", ak1.argTypeStr)
   211                     .replaceAll("#A2", ak2.argTypeStr)
   212                     .replaceAll("#E1", ek1.exceptionStr)
   213                     .replaceAll("#E2", ek2.exceptionStr);
   214         }
   216         @Override
   217         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   218             return source;
   219         }
   220     }
   222     public void run() {
   223         JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
   224                 Arrays.asList("-XDverboseResolution=all,-predef,-internal,-object-init"),
   225                 null, Arrays.asList(source));
   226         try {
   227             ct.analyze();
   228         } catch (Throwable ex) {
   229             throw new
   230                 AssertionError("Error thron when analyzing the following source:\n" +
   231                     source.getCharContent(true));
   232         }
   233         check();
   234     }
   236     void check() {
   237         checkCount.incrementAndGet();
   239         if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2))
   240             return;
   242         if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2))
   243             return;
   245         boolean m1MoreSpecific = moreSpecific(rt1, rt2, ek1, ek2, ak1, ak2);
   246         boolean m2MoreSpecific = moreSpecific(rt2, rt1, ek2, ek1, ak2, ak1);
   248         boolean ambiguous = (m1MoreSpecific == m2MoreSpecific);
   250         if (ambiguous != diagChecker.ambiguityFound) {
   251             throw new Error("invalid diagnostics for source:\n" +
   252                 source.getCharContent(true) +
   253                 "\nAmbiguity found: " + diagChecker.ambiguityFound +
   254                 "\nm1 more specific: " + m1MoreSpecific +
   255                 "\nm2 more specific: " + m2MoreSpecific +
   256                 "\nexpected ambiguity: " + ambiguous);
   257         }
   259         if (!ambiguous) {
   260             String sigToCheck = m1MoreSpecific ? "m(SAM1)" : "m(SAM2)";
   261             if (!sigToCheck.equals(diagChecker.mostSpecificSig)) {
   262                 throw new Error("invalid most specific method selected:\n" +
   263                 source.getCharContent(true) +
   264                 "\nMost specific found: " + diagChecker.mostSpecificSig +
   265                 "\nm1 more specific: " + m1MoreSpecific +
   266                 "\nm2 more specific: " + m2MoreSpecific);
   267             }
   268         }
   269     }
   271     boolean moreSpecific(RetTypeKind rk1, RetTypeKind rk2, ExceptionKind ek1,
   272             ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) {
   273         if (!rk1.moreSpecificThan(rk2))
   274             return false;
   276         if (ak1 != ak2)
   277             return false;
   279         return true;
   280     }
   282     static class DiagnosticChecker
   283         implements javax.tools.DiagnosticListener<JavaFileObject> {
   285         boolean ambiguityFound;
   286         String mostSpecificSig;
   288         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   289             try {
   290                 if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
   291                         diagnostic.getCode().equals("compiler.err.ref.ambiguous")) {
   292                     ambiguityFound = true;
   293                 } else if (diagnostic.getKind() == Diagnostic.Kind.NOTE &&
   294                         diagnostic.getCode()
   295                         .equals("compiler.note.verbose.resolve.multi")) {
   296                     ClientCodeWrapper.DiagnosticSourceUnwrapper dsu =
   297                         (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic;
   298                     JCDiagnostic.MultilineDiagnostic mdiag =
   299                         (JCDiagnostic.MultilineDiagnostic)dsu.d;
   300                     int mostSpecificIndex = (Integer)mdiag.getArgs()[2];
   301                     mostSpecificSig =
   302                         ((JCDiagnostic)mdiag.getSubdiagnostics()
   303                             .get(mostSpecificIndex)).getArgs()[1].toString();
   304                 }
   305             } catch (RuntimeException t) {
   306                 t.printStackTrace();
   307                 throw t;
   308             }
   309         }
   310     }
   312 }

mercurial