langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java
changeset 15040 99fd9483d3f0
parent 14725 65836e833f59
child 15375 d2529dc91d77
equal deleted inserted replaced
15039:80190ab051c0 15040:99fd9483d3f0
     1 /*
     1 /*
     2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    23 
    23 
    24 /*
    24 /*
    25  * @test
    25  * @test
    26  * @bug 8002099
    26  * @bug 8002099
    27  * @summary Add support for intersection types in cast expression
    27  * @summary Add support for intersection types in cast expression
       
    28  * @library ../../lib
       
    29  * @build JavacTestingAbstractThreadedTest
       
    30  * @run main/timeout=360 IntersectionTypeCastTest
    28  */
    31  */
    29 
    32 
    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;
    33 import java.net.URI;
    34 import java.util.Arrays;
    34 import java.util.Arrays;
    35 import javax.tools.Diagnostic;
    35 import javax.tools.Diagnostic;
    36 import javax.tools.JavaCompiler;
    36 import javax.tools.JavaCompiler;
    37 import javax.tools.JavaFileObject;
    37 import javax.tools.JavaFileObject;
    38 import javax.tools.SimpleJavaFileObject;
    38 import javax.tools.SimpleJavaFileObject;
    39 import javax.tools.StandardJavaFileManager;
       
    40 import javax.tools.ToolProvider;
    39 import javax.tools.ToolProvider;
    41 
    40 
    42 public class IntersectionTypeCastTest {
    41 import com.sun.source.util.JavacTask;
    43 
    42 import com.sun.tools.javac.util.List;
    44     static int checkCount = 0;
    43 import com.sun.tools.javac.util.ListBuffer;
       
    44 
       
    45 public class IntersectionTypeCastTest
       
    46     extends JavacTestingAbstractThreadedTest
       
    47     implements Runnable {
    45 
    48 
    46     interface Type {
    49     interface Type {
    47         boolean subtypeOf(Type that);
    50         boolean subtypeOf(Type that);
    48         String asString();
    51         String asString();
    49         boolean isClass();
    52         boolean isClass();
    57 
    60 
    58         String declStr;
    61         String declStr;
    59         String typeStr;
    62         String typeStr;
    60         InterfaceKind superInterface;
    63         InterfaceKind superInterface;
    61 
    64 
    62         InterfaceKind(String declStr, String typeStr, InterfaceKind superInterface) {
    65         InterfaceKind(String declStr, String typeStr,
       
    66                 InterfaceKind superInterface) {
    63             this.declStr = declStr;
    67             this.declStr = declStr;
    64             this.typeStr = typeStr;
    68             this.typeStr = typeStr;
    65             this.superInterface = superInterface;
    69             this.superInterface = superInterface;
    66         }
    70         }
    67 
    71 
    68         @Override
    72         @Override
    69         public boolean subtypeOf(Type that) {
    73         public boolean subtypeOf(Type that) {
    70             return this == that || superInterface == that || that == ClassKind.OBJECT;
    74             return this == that || superInterface == that ||
       
    75                    that == ClassKind.OBJECT;
    71         }
    76         }
    72 
    77 
    73         @Override
    78         @Override
    74         public String asString() {
    79         public String asString() {
    75             return typeStr;
    80             return typeStr;
    86         }
    91         }
    87     }
    92     }
    88 
    93 
    89     enum ClassKind implements Type {
    94     enum ClassKind implements Type {
    90         OBJECT(null, "Object"),
    95         OBJECT(null, "Object"),
    91         CA("#M class CA implements A { }\n", "CA", InterfaceKind.A),
    96         CA("#M class CA implements A { }\n", "CA",
    92         CB("#M class CB implements B { }\n", "CB", InterfaceKind.B),
    97            InterfaceKind.A),
    93         CAB("#M class CAB implements A, B { }\n", "CAB", InterfaceKind.A, InterfaceKind.B),
    98         CB("#M class CB implements B { }\n", "CB",
    94         CC("#M class CC implements C { }\n", "CC", InterfaceKind.C, InterfaceKind.A),
    99            InterfaceKind.B),
    95         CCA("#M class CCA implements C, A { }\n", "CCA", InterfaceKind.C, InterfaceKind.A),
   100         CAB("#M class CAB implements A, B { }\n", "CAB",
    96         CCB("#M class CCB implements C, B { }\n", "CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
   101             InterfaceKind.A, InterfaceKind.B),
    97         CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
   102         CC("#M class CC implements C { }\n", "CC",
       
   103            InterfaceKind.C, InterfaceKind.A),
       
   104         CCA("#M class CCA implements C, A { }\n", "CCA",
       
   105             InterfaceKind.C, InterfaceKind.A),
       
   106         CCB("#M class CCB implements C, B { }\n", "CCB",
       
   107             InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
       
   108         CCAB("#M class CCAB implements C, A, B { }\n", "CCAB",
       
   109              InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
    98 
   110 
    99         String declTemplate;
   111         String declTemplate;
   100         String typeStr;
   112         String typeStr;
   101         List<InterfaceKind> superInterfaces;
   113         List<InterfaceKind> superInterfaces;
   102 
   114 
   103         ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) {
   115         ClassKind(String declTemplate, String typeStr,
       
   116                 InterfaceKind... superInterfaces) {
   104             this.declTemplate = declTemplate;
   117             this.declTemplate = declTemplate;
   105             this.typeStr = typeStr;
   118             this.typeStr = typeStr;
   106             this.superInterfaces = List.from(superInterfaces);
   119             this.superInterfaces = List.from(superInterfaces);
   107         }
   120         }
   108 
   121 
   112                     "";
   125                     "";
   113         }
   126         }
   114 
   127 
   115         @Override
   128         @Override
   116         public boolean subtypeOf(Type that) {
   129         public boolean subtypeOf(Type that) {
   117             return this == that || superInterfaces.contains(that) || that == OBJECT;
   130             return this == that || superInterfaces.contains(that) ||
       
   131                     that == OBJECT;
   118         }
   132         }
   119 
   133 
   120         @Override
   134         @Override
   121         public String asString() {
   135         public String asString() {
   122             return typeStr;
   136             return typeStr;
   168             this.kind = kind;
   182             this.kind = kind;
   169             this.types = types;
   183             this.types = types;
   170         }
   184         }
   171 
   185 
   172         String getCast() {
   186         String getCast() {
   173             String temp = kind.castTemplate.replaceAll("#C", types[0].asString());
   187             String temp = kind.castTemplate.replaceAll("#C",
       
   188                     types[0].asString());
   174             for (int i = 0; i < kind.interfaceBounds ; i++) {
   189             for (int i = 0; i < kind.interfaceBounds ; i++) {
   175                 temp = temp.replace(String.format("#I%d", i), types[i + 1].asString());
   190                 temp = temp.replace(String.format("#I%d", i),
       
   191                                     types[i + 1].asString());
   176             }
   192             }
   177             return temp;
   193             return temp;
   178         }
   194         }
   179 
   195 
   180         boolean hasDuplicateTypes() {
   196         boolean hasDuplicateTypes() {
   193                 for (Type t2 : that.types) {
   209                 for (Type t2 : that.types) {
   194                     boolean compat =
   210                     boolean compat =
   195                             t1.subtypeOf(t2) ||
   211                             t1.subtypeOf(t2) ||
   196                             t2.subtypeOf(t1) ||
   212                             t2.subtypeOf(t1) ||
   197                             (t1.isInterface() && t2.isInterface()) || //side-cast (1)
   213                             (t1.isInterface() && t2.isInterface()) || //side-cast (1)
   198                             (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2)
   214                             (mod == ModifierKind.NONE &&
       
   215                             (t1.isInterface() != t2.isInterface())); //side-cast (2)
   199                     if (!compat) return false;
   216                     if (!compat) return false;
   200                 }
   217                 }
   201             }
   218             }
   202             return true;
   219             return true;
   203         }
   220         }
   204     }
   221     }
   205 
   222 
   206     public static void main(String... args) throws Exception {
   223     public static void main(String... args) throws Exception {
   207         //create default shared JavaCompiler - reused across multiple compilations
       
   208         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
       
   209         StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
       
   210 
       
   211         for (ModifierKind mod : ModifierKind.values()) {
   224         for (ModifierKind mod : ModifierKind.values()) {
   212             for (CastInfo cast1 : allCastInfo()) {
   225             for (CastInfo cast1 : allCastInfo()) {
   213                 for (CastInfo cast2 : allCastInfo()) {
   226                 for (CastInfo cast2 : allCastInfo()) {
   214                     new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm);
   227                     pool.execute(
       
   228                         new IntersectionTypeCastTest(mod, cast1, cast2));
   215                 }
   229                 }
   216             }
   230             }
   217         }
   231         }
   218         System.out.println("Total check executed: " + checkCount);
   232         checkAfterExec();
   219     }
   233     }
   220 
   234 
   221     static List<CastInfo> allCastInfo() {
   235     static List<CastInfo> allCastInfo() {
   222         ListBuffer<CastInfo> buf = ListBuffer.lb();
   236         ListBuffer<CastInfo> buf = ListBuffer.lb();
   223         for (CastKind kind : CastKind.values()) {
   237         for (CastKind kind : CastKind.values()) {
   233                             buf.append(new CastInfo(kind, clazz, intf1));
   247                             buf.append(new CastInfo(kind, clazz, intf1));
   234                             continue;
   248                             continue;
   235                         } else {
   249                         } else {
   236                             for (InterfaceKind intf2 : InterfaceKind.values()) {
   250                             for (InterfaceKind intf2 : InterfaceKind.values()) {
   237                                 if (kind.interfaceBounds == 2) {
   251                                 if (kind.interfaceBounds == 2) {
   238                                     buf.append(new CastInfo(kind, clazz, intf1, intf2));
   252                                     buf.append(
       
   253                                             new CastInfo(kind, clazz, intf1, intf2));
   239                                     continue;
   254                                     continue;
   240                                 } else {
   255                                 } else {
   241                                     for (InterfaceKind intf3 : InterfaceKind.values()) {
   256                                     for (InterfaceKind intf3 : InterfaceKind.values()) {
   242                                         buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3));
   257                                         buf.append(
       
   258                                                 new CastInfo(kind, clazz, intf1,
       
   259                                                              intf2, intf3));
   243                                         continue;
   260                                         continue;
   244                                     }
   261                                     }
   245                                 }
   262                                 }
   246                             }
   263                             }
   247                         }
   264                         }
   263         this.cast2 = cast2;
   280         this.cast2 = cast2;
   264         this.source = new JavaSource();
   281         this.source = new JavaSource();
   265         this.diagChecker = new DiagnosticChecker();
   282         this.diagChecker = new DiagnosticChecker();
   266     }
   283     }
   267 
   284 
       
   285     @Override
       
   286     public void run() {
       
   287         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
       
   288 
       
   289         JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker,
       
   290                 Arrays.asList("-XDallowIntersectionTypes"),
       
   291                 null, Arrays.asList(source));
       
   292         try {
       
   293             ct.analyze();
       
   294         } catch (Throwable ex) {
       
   295             throw new AssertionError("Error thrown when compiling the following code:\n" +
       
   296                     source.getCharContent(true));
       
   297         }
       
   298         check();
       
   299     }
       
   300 
   268     class JavaSource extends SimpleJavaFileObject {
   301     class JavaSource extends SimpleJavaFileObject {
   269 
   302 
   270         String bodyTemplate = "class Test {\n" +
   303         String bodyTemplate = "class Test {\n" +
   271                               "   void test() {\n" +
   304                               "   void test() {\n" +
   272                               "      Object o = #C1#C2null;\n" +
   305                               "      Object o = #C1#C2null;\n" +
   280                 source += ck.getDecl(mod);
   313                 source += ck.getDecl(mod);
   281             }
   314             }
   282             for (InterfaceKind ik : InterfaceKind.values()) {
   315             for (InterfaceKind ik : InterfaceKind.values()) {
   283                 source += ik.declStr;
   316                 source += ik.declStr;
   284             }
   317             }
   285             source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast());
   318             source += bodyTemplate.replaceAll("#C1", cast1.getCast()).
       
   319                     replaceAll("#C2", cast2.getCast());
   286         }
   320         }
   287 
   321 
   288         @Override
   322         @Override
   289         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   323         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   290             return source;
   324             return source;
   291         }
   325         }
   292     }
   326     }
   293 
   327 
   294     void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
       
   295         JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
       
   296                 Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source));
       
   297         try {
       
   298             ct.analyze();
       
   299         } catch (Throwable ex) {
       
   300             throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
       
   301         }
       
   302         check();
       
   303     }
       
   304 
       
   305     void check() {
   328     void check() {
   306         checkCount++;
   329         checkCount.incrementAndGet();
   307 
   330 
   308         boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes();
   331         boolean errorExpected = cast1.hasDuplicateTypes() ||
       
   332                 cast2.hasDuplicateTypes();
   309 
   333 
   310         errorExpected |= !cast2.compatibleWith(mod, cast1);
   334         errorExpected |= !cast2.compatibleWith(mod, cast1);
   311 
   335 
   312         if (errorExpected != diagChecker.errorFound) {
   336         if (errorExpected != diagChecker.errorFound) {
   313             throw new Error("invalid diagnostics for source:\n" +
   337             throw new Error("invalid diagnostics for source:\n" +
   315                 "\nFound error: " + diagChecker.errorFound +
   339                 "\nFound error: " + diagChecker.errorFound +
   316                 "\nExpected error: " + errorExpected);
   340                 "\nExpected error: " + errorExpected);
   317         }
   341         }
   318     }
   342     }
   319 
   343 
   320     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   344     static class DiagnosticChecker
       
   345         implements javax.tools.DiagnosticListener<JavaFileObject> {
   321 
   346 
   322         boolean errorFound;
   347         boolean errorFound;
   323 
   348 
   324         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   349         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   325             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   350             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   326                 errorFound = true;
   351                 errorFound = true;
   327             }
   352             }
   328         }
   353         }
   329     }
   354     }
       
   355 
   330 }
   356 }