test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

     1 /*
     2  * Copyright (c) 2012, 2014, 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 8002099 8010822
    27  * @summary Add support for intersection types in cast expression
    28  */
    30 import com.sun.source.util.JavacTask;
    31 import com.sun.tools.javac.util.ListBuffer;
    32 import java.net.URI;
    33 import java.util.ArrayList;
    34 import java.util.Arrays;
    35 import java.util.List;
    36 import javax.tools.Diagnostic;
    37 import javax.tools.JavaCompiler;
    38 import javax.tools.JavaFileObject;
    39 import javax.tools.SimpleJavaFileObject;
    40 import javax.tools.StandardJavaFileManager;
    41 import javax.tools.ToolProvider;
    43 public class IntersectionTargetTypeTest {
    45     static int checkCount = 0;
    47     enum BoundKind {
    48         INTF,
    49         CLASS;
    50     }
    52     enum MethodKind {
    53         NONE(false),
    54         ABSTRACT_M(true),
    55         DEFAULT_M(false),
    56         ABSTRACT_G(true),
    57         DEFAULT_G(false);
    59         boolean isAbstract;
    61         MethodKind(boolean isAbstract) {
    62             this.isAbstract = isAbstract;
    63         }
    64     }
    66     enum TypeKind {
    67         A("interface A { }\n", "A", BoundKind.INTF, MethodKind.NONE),
    68         B("interface B { default void m() { } }\n", "B", BoundKind.INTF, MethodKind.DEFAULT_M),
    69         C("interface C { void m(); }\n", "C", BoundKind.INTF, MethodKind.ABSTRACT_M),
    70         D("interface D extends B { }\n", "D", BoundKind.INTF, MethodKind.DEFAULT_M),
    71         E("interface E extends C { }\n", "E", BoundKind.INTF, MethodKind.ABSTRACT_M),
    72         F("interface F extends C { void g(); }\n", "F", BoundKind.INTF, MethodKind.ABSTRACT_G, MethodKind.ABSTRACT_M),
    73         G("interface G extends B { void g(); }\n", "G", BoundKind.INTF, MethodKind.ABSTRACT_G, MethodKind.DEFAULT_M),
    74         H("interface H extends A { void g(); }\n", "H", BoundKind.INTF, MethodKind.ABSTRACT_G),
    75         OBJECT("", "Object", BoundKind.CLASS),
    76         STRING("", "String", BoundKind.CLASS);
    78         String declStr;
    79         String typeStr;
    80         BoundKind boundKind;
    81         MethodKind[] methodKinds;
    83         private TypeKind(String declStr, String typeStr, BoundKind boundKind, MethodKind... methodKinds) {
    84             this.declStr = declStr;
    85             this.typeStr = typeStr;
    86             this.boundKind = boundKind;
    87             this.methodKinds = methodKinds;
    88         }
    90         boolean compatibleSupertype(TypeKind tk) {
    91             if (tk == this) return true;
    92             switch (tk) {
    93                 case B:
    94                     return this != C && this != E && this != F;
    95                 case C:
    96                     return this != B && this != C && this != D && this != G;
    97                 case D: return compatibleSupertype(B);
    98                 case E:
    99                 case F: return compatibleSupertype(C);
   100                 case G: return compatibleSupertype(B);
   101                 case H: return compatibleSupertype(A);
   102                 default:
   103                     return true;
   104             }
   105         }
   106     }
   108     enum CastKind {
   109         ONE_ARY("(#B0)", 1),
   110         TWO_ARY("(#B0 & #B1)", 2),
   111         THREE_ARY("(#B0 & #B1 & #B2)", 3);
   113         String castTemplate;
   114         int nbounds;
   116         CastKind(String castTemplate, int nbounds) {
   117             this.castTemplate = castTemplate;
   118             this.nbounds = nbounds;
   119         }
   120     }
   122     enum ExpressionKind {
   123         LAMBDA("()->{}", true),
   124         MREF("this::m", true),
   125         //COND_LAMBDA("(true ? ()->{} : ()->{})", true), re-enable if spec allows this
   126         //COND_MREF("(true ? this::m : this::m)", true),
   127         STANDALONE("null", false);
   129         String exprString;
   130         boolean isFunctional;
   132         private ExpressionKind(String exprString, boolean isFunctional) {
   133             this.exprString = exprString;
   134             this.isFunctional = isFunctional;
   135         }
   136     }
   138     static class CastInfo {
   139         CastKind kind;
   140         TypeKind[] types;
   142         CastInfo(CastKind kind, TypeKind... types) {
   143             this.kind = kind;
   144             this.types = types;
   145         }
   147         String getCast() {
   148             String temp = kind.castTemplate;
   149             for (int i = 0; i < kind.nbounds ; i++) {
   150                 temp = temp.replace(String.format("#B%d", i), types[i].typeStr);
   151             }
   152             return temp;
   153         }
   155         boolean wellFormed() {
   156             //check for duplicate types
   157             for (int i = 0 ; i < types.length ; i++) {
   158                 for (int j = 0 ; j < types.length ; j++) {
   159                     if (i != j && types[i] == types[j]) {
   160                         return false;
   161                     }
   162                 }
   163             }
   164             //check that classes only appear as first bound
   165             boolean classOk = true;
   166             for (int i = 0 ; i < types.length ; i++) {
   167                 if (types[i].boundKind == BoundKind.CLASS &&
   168                         !classOk) {
   169                     return false;
   170                 }
   171                 classOk = false;
   172             }
   173             //check that supertypes are mutually compatible
   174             for (int i = 0 ; i < types.length ; i++) {
   175                 for (int j = 0 ; j < types.length ; j++) {
   176                     if (!types[i].compatibleSupertype(types[j]) && i != j) {
   177                         return false;
   178                     }
   179                 }
   180             }
   181             return true;
   182         }
   183     }
   185     public static void main(String... args) throws Exception {
   186         //create default shared JavaCompiler - reused across multiple compilations
   187         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   188         StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
   190         for (CastInfo cInfo : allCastInfo()) {
   191             for (ExpressionKind ek : ExpressionKind.values()) {
   192                 new IntersectionTargetTypeTest(cInfo, ek).run(comp, fm);
   193             }
   194         }
   195         System.out.println("Total check executed: " + checkCount);
   196     }
   198     static List<CastInfo> allCastInfo() {
   199         ListBuffer<CastInfo> buf = new ListBuffer<>();
   200         for (CastKind kind : CastKind.values()) {
   201             for (TypeKind b1 : TypeKind.values()) {
   202                 if (kind.nbounds == 1) {
   203                     buf.append(new CastInfo(kind, b1));
   204                     continue;
   205                 } else {
   206                     for (TypeKind b2 : TypeKind.values()) {
   207                         if (kind.nbounds == 2) {
   208                             buf.append(new CastInfo(kind, b1, b2));
   209                             continue;
   210                         } else {
   211                             for (TypeKind b3 : TypeKind.values()) {
   212                                 buf.append(new CastInfo(kind, b1, b2, b3));
   213                             }
   214                         }
   215                     }
   216                 }
   217             }
   218         }
   219         return buf.toList();
   220     }
   222     CastInfo cInfo;
   223     ExpressionKind ek;
   224     JavaSource source;
   225     DiagnosticChecker diagChecker;
   227     IntersectionTargetTypeTest(CastInfo cInfo, ExpressionKind ek) {
   228         this.cInfo = cInfo;
   229         this.ek = ek;
   230         this.source = new JavaSource();
   231         this.diagChecker = new DiagnosticChecker();
   232     }
   234     class JavaSource extends SimpleJavaFileObject {
   236         String bodyTemplate = "class Test {\n" +
   237                               "   void m() { }\n" +
   238                               "   void test() {\n" +
   239                               "      Object o = #C#E;\n" +
   240                               "   } }";
   242         String source = "";
   244         public JavaSource() {
   245             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   246             for (TypeKind tk : TypeKind.values()) {
   247                 source += tk.declStr;
   248             }
   249             source += bodyTemplate.replaceAll("#C", cInfo.getCast()).replaceAll("#E", ek.exprString);
   250         }
   252         @Override
   253         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   254             return source;
   255         }
   256     }
   258     void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
   259         JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
   260                 null, null, Arrays.asList(source));
   261         try {
   262             ct.analyze();
   263         } catch (Throwable ex) {
   264             throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
   265         }
   266         check();
   267     }
   269     void check() {
   270         checkCount++;
   272         boolean errorExpected = !cInfo.wellFormed();
   274         if (ek.isFunctional) {
   275             List<MethodKind> mks = new ArrayList<>();
   276             for (TypeKind tk : cInfo.types) {
   277                 if (tk.boundKind == BoundKind.CLASS) {
   278                     errorExpected = true;
   279                     break;
   280                 } else {
   281                     mks = mergeMethods(mks, Arrays.asList(tk.methodKinds));
   282                 }
   283             }
   284             int abstractCount = 0;
   285             for (MethodKind mk : mks) {
   286                 if (mk.isAbstract) {
   287                     abstractCount++;
   288                 }
   289             }
   290             errorExpected |= abstractCount != 1;
   291         }
   293         if (errorExpected != diagChecker.errorFound) {
   294             throw new Error("invalid diagnostics for source:\n" +
   295                 source.getCharContent(true) +
   296                 "\nFound error: " + diagChecker.errorFound +
   297                 "\nExpected error: " + errorExpected);
   298         }
   299     }
   301     List<MethodKind> mergeMethods(List<MethodKind> l1, List<MethodKind> l2) {
   302         List<MethodKind> mergedMethods = new ArrayList<>(l1);
   303         for (MethodKind mk2 : l2) {
   304             boolean add = !mergedMethods.contains(mk2);
   305             switch (mk2) {
   306                 case ABSTRACT_G:
   307                     add = add && !mergedMethods.contains(MethodKind.DEFAULT_G);
   308                     break;
   309                 case ABSTRACT_M:
   310                     add = add && !mergedMethods.contains(MethodKind.DEFAULT_M);
   311                     break;
   312                 case DEFAULT_G:
   313                     mergedMethods.remove(MethodKind.ABSTRACT_G);
   314                 case DEFAULT_M:
   315                     mergedMethods.remove(MethodKind.ABSTRACT_M);
   316                 case NONE:
   317                     add = false;
   318                     break;
   319             }
   320             if (add) {
   321                 mergedMethods.add(mk2);
   322             }
   323         }
   324         return mergedMethods;
   325     }
   327     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   329         boolean errorFound;
   331         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   332             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   333                 errorFound = true;
   334             }
   335         }
   336     }
   337 }

mercurial