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

Mon, 21 Jan 2013 20:14:39 +0000

author
mcimadamore
date
Mon, 21 Jan 2013 20:14:39 +0000
changeset 1511
c7c41a044e7c
parent 1436
f6f1fd261f57
child 1678
c635a966ce84
permissions
-rw-r--r--

8006566: Remove transient lambda-related guards from JavacParser
Summary: Remove transitional internal flag for allowing intersection types in cast
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2012, 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
    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.List;
    32 import com.sun.tools.javac.util.ListBuffer;
    33 import java.net.URI;
    34 import java.util.Arrays;
    35 import javax.tools.Diagnostic;
    36 import javax.tools.JavaCompiler;
    37 import javax.tools.JavaFileObject;
    38 import javax.tools.SimpleJavaFileObject;
    39 import javax.tools.StandardJavaFileManager;
    40 import javax.tools.ToolProvider;
    42 public class IntersectionTargetTypeTest {
    44     static int checkCount = 0;
    46     enum BoundKind {
    47         INTF,
    48         CLASS,
    49         SAM,
    50         ZAM;
    51     }
    53     enum MethodKind {
    54         NONE,
    55         ABSTRACT,
    56         DEFAULT;
    57     }
    59     enum TypeKind {
    60         A("interface A { }\n", "A", BoundKind.ZAM),
    61         B("interface B { default void m() { } }\n", "B", BoundKind.ZAM),
    62         C("interface C { void m(); }\n", "C", BoundKind.SAM),
    63         D("interface D extends B { }\n", "D", BoundKind.ZAM),
    64         E("interface E extends C { }\n", "E", BoundKind.SAM),
    65         F("interface F extends C { void g(); }\n", "F", BoundKind.INTF),
    66         G("interface G extends B { void g(); }\n", "G", BoundKind.SAM),
    67         H("interface H extends A { void g(); }\n", "H", BoundKind.SAM),
    68         OBJECT("", "Object", BoundKind.CLASS),
    69         STRING("", "String", BoundKind.CLASS);
    71         String declStr;
    72         String typeStr;
    73         BoundKind boundKind;
    75         private TypeKind(String declStr, String typeStr, BoundKind boundKind) {
    76             this.declStr = declStr;
    77             this.typeStr = typeStr;
    78             this.boundKind = boundKind;
    79         }
    81         boolean compatibleSupertype(TypeKind tk) {
    82             if (tk == this) return true;
    83             switch (tk) {
    84                 case B:
    85                     return this != C && this != E && this != F;
    86                 case C:
    87                     return this != B && this != C && this != D && this != G;
    88                 case D: return compatibleSupertype(B);
    89                 case E:
    90                 case F: return compatibleSupertype(C);
    91                 case G: return compatibleSupertype(B);
    92                 case H: return compatibleSupertype(A);
    93                 default:
    94                     return true;
    95             }
    96         }
    97     }
    99     enum CastKind {
   100         ONE_ARY("(#B0)", 1),
   101         TWO_ARY("(#B0 & #B1)", 2),
   102         THREE_ARY("(#B0 & #B1 & #B2)", 3);
   104         String castTemplate;
   105         int nbounds;
   107         CastKind(String castTemplate, int nbounds) {
   108             this.castTemplate = castTemplate;
   109             this.nbounds = nbounds;
   110         }
   111     }
   113     enum ExpressionKind {
   114         LAMBDA("()->{}", true),
   115         MREF("this::m", true),
   116         //COND_LAMBDA("(true ? ()->{} : ()->{})", true), re-enable if spec allows this
   117         //COND_MREF("(true ? this::m : this::m)", true),
   118         STANDALONE("null", false);
   120         String exprString;
   121         boolean isFunctional;
   123         private ExpressionKind(String exprString, boolean isFunctional) {
   124             this.exprString = exprString;
   125             this.isFunctional = isFunctional;
   126         }
   127     }
   129     static class CastInfo {
   130         CastKind kind;
   131         TypeKind[] types;
   133         CastInfo(CastKind kind, TypeKind... types) {
   134             this.kind = kind;
   135             this.types = types;
   136         }
   138         String getCast() {
   139             String temp = kind.castTemplate;
   140             for (int i = 0; i < kind.nbounds ; i++) {
   141                 temp = temp.replace(String.format("#B%d", i), types[i].typeStr);
   142             }
   143             return temp;
   144         }
   146         boolean wellFormed() {
   147             //check for duplicate types
   148             for (int i = 0 ; i < types.length ; i++) {
   149                 for (int j = 0 ; j < types.length ; j++) {
   150                     if (i != j && types[i] == types[j]) {
   151                         return false;
   152                     }
   153                 }
   154             }
   155             //check that classes only appear as first bound
   156             boolean classOk = true;
   157             for (int i = 0 ; i < types.length ; i++) {
   158                 if (types[i].boundKind == BoundKind.CLASS &&
   159                         !classOk) {
   160                     return false;
   161                 }
   162                 classOk = false;
   163             }
   164             //check that supertypes are mutually compatible
   165             for (int i = 0 ; i < types.length ; i++) {
   166                 for (int j = 0 ; j < types.length ; j++) {
   167                     if (!types[i].compatibleSupertype(types[j]) && i != j) {
   168                         return false;
   169                     }
   170                 }
   171             }
   172             return true;
   173         }
   174     }
   176     public static void main(String... args) throws Exception {
   177         //create default shared JavaCompiler - reused across multiple compilations
   178         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   179         StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
   181         for (CastInfo cInfo : allCastInfo()) {
   182             for (ExpressionKind ek : ExpressionKind.values()) {
   183                 new IntersectionTargetTypeTest(cInfo, ek).run(comp, fm);
   184             }
   185         }
   186         System.out.println("Total check executed: " + checkCount);
   187     }
   189     static List<CastInfo> allCastInfo() {
   190         ListBuffer<CastInfo> buf = ListBuffer.lb();
   191         for (CastKind kind : CastKind.values()) {
   192             for (TypeKind b1 : TypeKind.values()) {
   193                 if (kind.nbounds == 1) {
   194                     buf.append(new CastInfo(kind, b1));
   195                     continue;
   196                 } else {
   197                     for (TypeKind b2 : TypeKind.values()) {
   198                         if (kind.nbounds == 2) {
   199                             buf.append(new CastInfo(kind, b1, b2));
   200                             continue;
   201                         } else {
   202                             for (TypeKind b3 : TypeKind.values()) {
   203                                 buf.append(new CastInfo(kind, b1, b2, b3));
   204                             }
   205                         }
   206                     }
   207                 }
   208             }
   209         }
   210         return buf.toList();
   211     }
   213     CastInfo cInfo;
   214     ExpressionKind ek;
   215     JavaSource source;
   216     DiagnosticChecker diagChecker;
   218     IntersectionTargetTypeTest(CastInfo cInfo, ExpressionKind ek) {
   219         this.cInfo = cInfo;
   220         this.ek = ek;
   221         this.source = new JavaSource();
   222         this.diagChecker = new DiagnosticChecker();
   223     }
   225     class JavaSource extends SimpleJavaFileObject {
   227         String bodyTemplate = "class Test {\n" +
   228                               "   void m() { }\n" +
   229                               "   void test() {\n" +
   230                               "      Object o = #C#E;\n" +
   231                               "   } }";
   233         String source = "";
   235         public JavaSource() {
   236             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   237             for (TypeKind tk : TypeKind.values()) {
   238                 source += tk.declStr;
   239             }
   240             source += bodyTemplate.replaceAll("#C", cInfo.getCast()).replaceAll("#E", ek.exprString);
   241         }
   243         @Override
   244         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   245             return source;
   246         }
   247     }
   249     void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
   250         JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
   251                 null, null, Arrays.asList(source));
   252         try {
   253             ct.analyze();
   254         } catch (Throwable ex) {
   255             throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
   256         }
   257         check();
   258     }
   260     void check() {
   261         checkCount++;
   263         boolean errorExpected = !cInfo.wellFormed();
   265         if (ek.isFunctional) {
   266             //first bound must be a SAM
   267             errorExpected |= cInfo.types[0].boundKind != BoundKind.SAM;
   268             if (cInfo.types.length > 1) {
   269                 //additional bounds must be ZAMs
   270                 for (int i = 1; i < cInfo.types.length; i++) {
   271                     errorExpected |= cInfo.types[i].boundKind != BoundKind.ZAM;
   272                 }
   273             }
   274         }
   276         if (errorExpected != diagChecker.errorFound) {
   277             throw new Error("invalid diagnostics for source:\n" +
   278                 source.getCharContent(true) +
   279                 "\nFound error: " + diagChecker.errorFound +
   280                 "\nExpected error: " + errorExpected);
   281         }
   282     }
   284     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   286         boolean errorFound;
   288         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   289             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   290                 errorFound = true;
   291             }
   292         }
   293     }
   294 }

mercurial