langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java
changeset 32454 b0ac04e0fefe
parent 30730 d3ce7619db2c
child 41526 265017792980
equal deleted inserted replaced
32453:8eebd1f0b8ea 32454:b0ac04e0fefe
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
    24 /*
    24 /*
    25  * @test
    25  * @test
    26  * @bug 7062745 8006694
    26  * @bug 7062745 8006694 8129962
    27  * @summary  Regression: difference in overload resolution when two methods
    27  * @summary  Regression: difference in overload resolution when two methods
    28  *  are maximally specific
    28  *  are maximally specific
    29  *  temporarily workaround combo tests are causing time out in several platforms
    29  *  temporarily workaround combo tests are causing time out in several platforms
    30  * @library ../../../lib
    30  * @library /tools/javac/lib
    31  * @modules jdk.compiler
    31  * @modules jdk.compiler/com.sun.tools.javac.api
    32  * @build JavacTestingAbstractThreadedTest
    32  *          jdk.compiler/com.sun.tools.javac.code
    33  * @run main/othervm GenericOverrideTest
    33  *          jdk.compiler/com.sun.tools.javac.comp
       
    34  *          jdk.compiler/com.sun.tools.javac.main
       
    35  *          jdk.compiler/com.sun.tools.javac.tree
       
    36  *          jdk.compiler/com.sun.tools.javac.util
       
    37  * @build combo.ComboTestHelper
       
    38  * @run main GenericOverrideTest
    34  */
    39  */
    35 
    40 
    36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
    41 import java.io.IOException;
    37 // see JDK-8006746
    42 
    38 
    43 import combo.ComboInstance;
    39 import java.net.URI;
    44 import combo.ComboParameter;
    40 import java.util.Arrays;
    45 import combo.ComboTask.Result;
    41 import javax.tools.Diagnostic;
    46 import combo.ComboTestHelper;
    42 import javax.tools.JavaFileObject;
    47 
    43 import javax.tools.SimpleJavaFileObject;
    48 public class GenericOverrideTest extends ComboInstance<GenericOverrideTest> {
    44 import com.sun.source.util.JavacTask;
       
    45 
       
    46 public class GenericOverrideTest
       
    47     extends JavacTestingAbstractThreadedTest
       
    48     implements Runnable {
       
    49 
    49 
    50     enum SourceLevel {
    50     enum SourceLevel {
    51         SOURCE_7("-source", "7"),
    51         SOURCE_7("-source", "7"),
    52         SOURCE_DEFAULT();
    52         SOURCE_DEFAULT();
    53 
    53 
    56         SourceLevel(String... opts) {
    56         SourceLevel(String... opts) {
    57             this.opts = opts;
    57             this.opts = opts;
    58         }
    58         }
    59     }
    59     }
    60 
    60 
    61     enum SignatureKind {
    61     enum SignatureKind implements ComboParameter {
    62         NON_GENERIC(""),
    62         NON_GENERIC(""),
    63         GENERIC("<X>");
    63         GENERIC("<X>");
    64 
    64 
    65         String paramStr;
    65         String paramStr;
    66 
    66 
    67         private SignatureKind(String paramStr) {
    67         SignatureKind(String paramStr) {
    68             this.paramStr = paramStr;
    68             this.paramStr = paramStr;
    69         }
    69         }
    70     }
    70 
    71 
    71         @Override
    72     enum ReturnTypeKind {
    72         public String expand(String optParameter) {
       
    73             return paramStr;
       
    74         }
       
    75     }
       
    76 
       
    77     enum ReturnTypeKind implements ComboParameter {
    73         LIST("List"),
    78         LIST("List"),
    74         ARRAYLIST("ArrayList");
    79         ARRAYLIST("ArrayList");
    75 
    80 
    76         String retStr;
    81         String retStr;
    77 
    82 
    78         private ReturnTypeKind(String retStr) {
    83         ReturnTypeKind(String retStr) {
    79             this.retStr = retStr;
    84             this.retStr = retStr;
    80         }
    85         }
    81 
    86 
    82         boolean moreSpecificThan(ReturnTypeKind that) {
    87         boolean moreSpecificThan(ReturnTypeKind that) {
    83             switch (this) {
    88             switch (this) {
    86                 case ARRAYLIST:
    91                 case ARRAYLIST:
    87                     return that == LIST || that == ARRAYLIST;
    92                     return that == LIST || that == ARRAYLIST;
    88                 default: throw new AssertionError("Unexpected ret kind: " + this);
    93                 default: throw new AssertionError("Unexpected ret kind: " + this);
    89             }
    94             }
    90         }
    95         }
    91     }
    96 
    92 
    97         @Override
    93     enum TypeArgumentKind {
    98         public String expand(String optParameter) {
       
    99             return retStr;
       
   100         }
       
   101     }
       
   102 
       
   103     enum TypeArgumentKind implements ComboParameter {
    94         NONE(""),
   104         NONE(""),
    95         UNBOUND("<?>"),
   105         UNBOUND("<?>"),
    96         INTEGER("<Number>"),
   106         INTEGER("<Number>"),
    97         NUMBER("<Integer>"),
   107         NUMBER("<Integer>"),
    98         TYPEVAR("<X>");
   108         TYPEVAR("<X>");
    99 
   109 
   100         String typeargStr;
   110         String typeargStr;
   101 
   111 
   102         private TypeArgumentKind(String typeargStr) {
   112         TypeArgumentKind(String typeargStr) {
   103             this.typeargStr = typeargStr;
   113             this.typeargStr = typeargStr;
   104         }
   114         }
   105 
   115 
   106         boolean compatibleWith(SignatureKind sig) {
   116         boolean compatibleWith(SignatureKind sig) {
   107             switch (this) {
   117             switch (this) {
   139                 case TYPEVAR:
   149                 case TYPEVAR:
   140                     return true;
   150                     return true;
   141                 default: throw new AssertionError("Unexpected typearg kind: " + this);
   151                 default: throw new AssertionError("Unexpected typearg kind: " + this);
   142             }
   152             }
   143         }
   153         }
       
   154 
       
   155         @Override
       
   156         public String expand(String optParameter) {
       
   157             return typeargStr;
       
   158         }
   144     }
   159     }
   145 
   160 
   146     public static void main(String... args) throws Exception {
   161     public static void main(String... args) throws Exception {
   147         for (SignatureKind sig1 : SignatureKind.values()) {
   162         new ComboTestHelper<GenericOverrideTest>()
   148             for (ReturnTypeKind rt1 : ReturnTypeKind.values()) {
   163                 .withFilter(GenericOverrideTest::argMismatchFilter)
   149                 for (TypeArgumentKind ta1 : TypeArgumentKind.values()) {
   164                 .withDimension("SOURCE", (x, level) -> x.level = level, SourceLevel.values())
   150                     if (!ta1.compatibleWith(sig1)) continue;
   165                 .withArrayDimension("SIG", (x, sig, idx) -> x.sigs[idx] = sig, 2, SignatureKind.values())
   151                     for (SignatureKind sig2 : SignatureKind.values()) {
   166                 .withArrayDimension("TARG", (x, targ, idx) -> x.targs[idx] = targ, 3, TypeArgumentKind.values())
   152                         for (ReturnTypeKind rt2 : ReturnTypeKind.values()) {
   167                 .withArrayDimension("RET", (x, ret, idx) -> x.rets[idx] = ret, 3, ReturnTypeKind.values())
   153                             for (TypeArgumentKind ta2 : TypeArgumentKind.values()) {
   168                 .run(GenericOverrideTest::new);
   154                                 if (!ta2.compatibleWith(sig2)) continue;
   169     }
   155                                 for (ReturnTypeKind rt3 : ReturnTypeKind.values()) {
   170 
   156                                     for (TypeArgumentKind ta3 : TypeArgumentKind.values()) {
   171     SignatureKind[] sigs = new SignatureKind[2];
   157                                         if (!ta3.compatibleWith(SignatureKind.NON_GENERIC))
   172     ReturnTypeKind[] rets = new ReturnTypeKind[3];
   158                                             continue;
   173     TypeArgumentKind[] targs = new TypeArgumentKind[3];
   159                                         for (SourceLevel level : SourceLevel.values()) {
       
   160                                             pool.execute(
       
   161                                                     new GenericOverrideTest(sig1,
       
   162                                                     rt1, ta1, sig2, rt2,
       
   163                                                     ta2, rt3, ta3, level));
       
   164                                         }
       
   165                                     }
       
   166                                 }
       
   167                             }
       
   168                         }
       
   169                     }
       
   170                 }
       
   171             }
       
   172         }
       
   173 
       
   174         checkAfterExec();
       
   175     }
       
   176 
       
   177     SignatureKind sig1, sig2;
       
   178     ReturnTypeKind rt1, rt2, rt3;
       
   179     TypeArgumentKind ta1, ta2, ta3;
       
   180     SourceLevel level;
   174     SourceLevel level;
   181     JavaSource source;
   175 
   182     DiagnosticChecker diagChecker;
   176     boolean argMismatchFilter() {
   183 
   177         return targs[0].compatibleWith(sigs[0]) &&
   184     GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1,
   178                 targs[1].compatibleWith(sigs[1]) &&
   185             SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2,
   179                 targs[2].compatibleWith(SignatureKind.NON_GENERIC);
   186             ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) {
   180     }
   187         this.sig1 = sig1;
   181 
   188         this.sig2 = sig2;
   182     String template = "import java.util.*;\n" +
   189         this.rt1 = rt1;
   183                       "interface A { #{SIG[0]} #{RET[0]}#{TARG[0]} m(); }\n" +
   190         this.rt2 = rt2;
   184                       "interface B { #{SIG[1]} #{RET[1]}#{TARG[1]} m(); }\n" +
   191         this.rt3 = rt3;
   185                       "interface AB extends A, B {}\n" +
   192         this.ta1 = ta1;
   186                       "class Test {\n" +
   193         this.ta2 = ta2;
   187                       "  void test(AB ab) { #{RET[2]}#{TARG[2]} n = ab.m(); }\n" +
   194         this.ta3 = ta3;
   188                       "}";
   195         this.level = level;
       
   196         this.source = new JavaSource();
       
   197         this.diagChecker = new DiagnosticChecker();
       
   198     }
       
   199 
       
   200     class JavaSource extends SimpleJavaFileObject {
       
   201 
       
   202         String template = "import java.util.*;\n" +
       
   203                           "interface A { #S1 #R1#TA1 m(); }\n" +
       
   204                           "interface B { #S2 #R2#TA2 m(); }\n" +
       
   205                           "interface AB extends A, B {}\n" +
       
   206                           "class Test {\n" +
       
   207                           "  void test(AB ab) { #R3#TA3 n = ab.m(); }\n" +
       
   208                           "}";
       
   209 
       
   210         String source;
       
   211 
       
   212         public JavaSource() {
       
   213             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
       
   214             source = template.replace("#S1", sig1.paramStr).
       
   215                     replace("#S2", sig2.paramStr).
       
   216                     replace("#R1", rt1.retStr).
       
   217                     replace("#R2", rt2.retStr).
       
   218                     replace("#R3", rt3.retStr).
       
   219                     replace("#TA1", ta1.typeargStr).
       
   220                     replace("#TA2", ta2.typeargStr).
       
   221                     replace("#TA3", ta3.typeargStr);
       
   222         }
       
   223 
       
   224         @Override
       
   225         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       
   226             return source;
       
   227         }
       
   228     }
       
   229 
   189 
   230     @Override
   190     @Override
   231     public void run() {
   191     public void doWork() throws IOException {
   232         JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
   192         check(newCompilationTask()
   233                 level.opts != null ? Arrays.asList(level.opts) : null,
   193                 .withOption("-XDuseUnsharedTable") //this test relies on predictable name indexes!
   234                 null, Arrays.asList(source));
   194                 .withOptions(level.opts)
   235         try {
   195                 .withSourceFromTemplate(template)
   236             ct.analyze();
   196                 .analyze());
   237         } catch (Throwable ex) {
   197     }
   238             throw new AssertionError("Error thrown when compiling the following code:\n" +
   198 
   239                     source.getCharContent(true));
   199     void check(Result<?> res) {
   240         }
       
   241         check();
       
   242     }
       
   243 
       
   244     void check() {
       
   245         checkCount.incrementAndGet();
       
   246 
       
   247         boolean errorExpected = false;
   200         boolean errorExpected = false;
   248         int mostSpecific = 0;
   201         int mostSpecific = 0;
   249 
   202 
   250         //first check that either |R1| <: |R2| or |R2| <: |R1|
   203         //first check that either |R1| <: |R2| or |R2| <: |R1|
   251         if (rt1 != rt2) {
   204         if (rets[0] != rets[1]) {
   252             if (!rt1.moreSpecificThan(rt2) &&
   205             if (!rets[0].moreSpecificThan(rets[1]) &&
   253                     !rt2.moreSpecificThan(rt1)) {
   206                     !rets[1].moreSpecificThan(rets[0])) {
   254                 errorExpected = true;
   207                 errorExpected = true;
   255             } else {
   208             } else {
   256                 mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2;
   209                 mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2;
   257             }
   210             }
   258         }
   211         }
   259 
   212 
   260         //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
   213         //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
   261         if (!errorExpected) {
   214         if (!errorExpected) {
   262             if (ta1 != ta2) {
   215             if (targs[0] != targs[1]) {
   263                 boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) ||
   216                 boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) ||
   264                         ta2.moreSpecificThan(ta1, true);
   217                         targs[1].moreSpecificThan(targs[0], true);
   265                 if (!ta1.moreSpecificThan(ta2, useStrictCheck) &&
   218                 if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) &&
   266                         !ta2.moreSpecificThan(ta1, useStrictCheck)) {
   219                         !targs[1].moreSpecificThan(targs[0], useStrictCheck)) {
   267                     errorExpected = true;
   220                     errorExpected = true;
   268                 } else {
   221                 } else {
   269                     int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2;
   222                     int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2;
   270                     if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
   223                     if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
   271                         errorExpected = mostSpecific == 1 ?
   224                         errorExpected = mostSpecific == 1 ?
   272                                 ta1 != TypeArgumentKind.NONE :
   225                                 targs[0] != TypeArgumentKind.NONE :
   273                                 ta2 != TypeArgumentKind.NONE;
   226                                 targs[1] != TypeArgumentKind.NONE;
   274                     } else {
   227                     } else {
   275                         mostSpecific = mostSpecific2;
   228                         mostSpecific = mostSpecific2;
   276                     }
   229                     }
   277                 }
   230                 }
   278             } else if (mostSpecific == 0) {
   231             } else if (mostSpecific == 0) {
   282             }
   235             }
   283         }
   236         }
   284 
   237 
   285         //finally, check that most specific return type is compatible with expected type
   238         //finally, check that most specific return type is compatible with expected type
   286         if (!errorExpected) {
   239         if (!errorExpected) {
   287             ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2;
   240             ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1];
   288             TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2;
   241             TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1];
   289             SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2;
   242             SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1];
   290 
   243 
   291             if (!msrt.moreSpecificThan(rt3) ||
   244             if (!msrt.moreSpecificThan(rets[2]) ||
   292                     !msta.assignableTo(ta3, mssig, level)) {
   245                     !msta.assignableTo(targs[2], mssig, level)) {
   293                 errorExpected = true;
   246                 errorExpected = true;
   294             }
   247             }
   295         }
   248         }
   296 
   249 
   297         if (errorExpected != diagChecker.errorFound) {
   250         if (errorExpected != res.hasErrors()) {
   298             throw new Error("invalid diagnostics for source:\n" +
   251             fail("invalid diagnostics for source:\n" +
   299                 source.getCharContent(true) +
   252                 res.compilationInfo() +
   300                 "\nFound error: " + diagChecker.errorFound +
   253                 "\nFound error: " + res.hasErrors() +
   301                 "\nExpected error: " + errorExpected);
   254                 "\nExpected error: " + errorExpected);
   302         }
   255         }
   303     }
   256     }
   304 
       
   305     static class DiagnosticChecker
       
   306         implements javax.tools.DiagnosticListener<JavaFileObject> {
       
   307 
       
   308         boolean errorFound;
       
   309 
       
   310         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
       
   311             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
       
   312                 errorFound = true;
       
   313             }
       
   314         }
       
   315     }
       
   316 
       
   317 }
   257 }