test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java	Wed Apr 27 01:34:52 2016 +0800
     1.3 @@ -0,0 +1,316 @@
     1.4 +/*
     1.5 + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + */
    1.26 +
    1.27 +/*
    1.28 + * @test
    1.29 + * @bug 7062745 8006694
    1.30 + * @summary  Regression: difference in overload resolution when two methods
    1.31 + *  are maximally specific
    1.32 + *  temporarily workaround combo tests are causing time out in several platforms
    1.33 + * @library ../../../lib
    1.34 + * @build JavacTestingAbstractThreadedTest
    1.35 + * @run main/othervm GenericOverrideTest
    1.36 + */
    1.37 +
    1.38 +// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
    1.39 +// see JDK-8006746
    1.40 +
    1.41 +import java.net.URI;
    1.42 +import java.util.Arrays;
    1.43 +import javax.tools.Diagnostic;
    1.44 +import javax.tools.JavaFileObject;
    1.45 +import javax.tools.SimpleJavaFileObject;
    1.46 +import com.sun.source.util.JavacTask;
    1.47 +
    1.48 +public class GenericOverrideTest
    1.49 +    extends JavacTestingAbstractThreadedTest
    1.50 +    implements Runnable {
    1.51 +
    1.52 +    enum SourceLevel {
    1.53 +        SOURCE_7("-source", "7"),
    1.54 +        SOURCE_DEFAULT();
    1.55 +
    1.56 +        String[] opts;
    1.57 +
    1.58 +        SourceLevel(String... opts) {
    1.59 +            this.opts = opts;
    1.60 +        }
    1.61 +    }
    1.62 +
    1.63 +    enum SignatureKind {
    1.64 +        NON_GENERIC(""),
    1.65 +        GENERIC("<X>");
    1.66 +
    1.67 +        String paramStr;
    1.68 +
    1.69 +        private SignatureKind(String paramStr) {
    1.70 +            this.paramStr = paramStr;
    1.71 +        }
    1.72 +    }
    1.73 +
    1.74 +    enum ReturnTypeKind {
    1.75 +        LIST("List"),
    1.76 +        ARRAYLIST("ArrayList");
    1.77 +
    1.78 +        String retStr;
    1.79 +
    1.80 +        private ReturnTypeKind(String retStr) {
    1.81 +            this.retStr = retStr;
    1.82 +        }
    1.83 +
    1.84 +        boolean moreSpecificThan(ReturnTypeKind that) {
    1.85 +            switch (this) {
    1.86 +                case LIST:
    1.87 +                    return that == this;
    1.88 +                case ARRAYLIST:
    1.89 +                    return that == LIST || that == ARRAYLIST;
    1.90 +                default: throw new AssertionError("Unexpected ret kind: " + this);
    1.91 +            }
    1.92 +        }
    1.93 +    }
    1.94 +
    1.95 +    enum TypeArgumentKind {
    1.96 +        NONE(""),
    1.97 +        UNBOUND("<?>"),
    1.98 +        INTEGER("<Number>"),
    1.99 +        NUMBER("<Integer>"),
   1.100 +        TYPEVAR("<X>");
   1.101 +
   1.102 +        String typeargStr;
   1.103 +
   1.104 +        private TypeArgumentKind(String typeargStr) {
   1.105 +            this.typeargStr = typeargStr;
   1.106 +        }
   1.107 +
   1.108 +        boolean compatibleWith(SignatureKind sig) {
   1.109 +            switch (this) {
   1.110 +                case TYPEVAR: return sig != SignatureKind.NON_GENERIC;
   1.111 +                default: return true;
   1.112 +            }
   1.113 +        }
   1.114 +
   1.115 +        boolean moreSpecificThan(TypeArgumentKind that, boolean strict) {
   1.116 +            switch (this) {
   1.117 +                case NONE:
   1.118 +                    return that == this || !strict;
   1.119 +                case UNBOUND:
   1.120 +                    return that == this || that == NONE;
   1.121 +                case INTEGER:
   1.122 +                case NUMBER:
   1.123 +                case TYPEVAR:
   1.124 +                    return that == this || that == NONE || that == UNBOUND;
   1.125 +                default: throw new AssertionError("Unexpected typearg kind: " + this);
   1.126 +            }
   1.127 +        }
   1.128 +
   1.129 +        boolean assignableTo(TypeArgumentKind that, SignatureKind sig, SourceLevel level) {
   1.130 +            switch (this) {
   1.131 +                case NONE:
   1.132 +                    //this case needs to workaround to javac's impl of 15.12.2.8 being too strict
   1.133 +                    //ideally should be just 'return true' (see 7067746/8015505)
   1.134 +                    return level == SourceLevel.SOURCE_DEFAULT ||
   1.135 +                            sig == SignatureKind.NON_GENERIC || that == NONE;
   1.136 +                case UNBOUND:
   1.137 +                    return that == this || that == NONE;
   1.138 +                case INTEGER:
   1.139 +                case NUMBER:
   1.140 +                    return that == this || that == NONE || that == UNBOUND;
   1.141 +                case TYPEVAR:
   1.142 +                    return true;
   1.143 +                default: throw new AssertionError("Unexpected typearg kind: " + this);
   1.144 +            }
   1.145 +        }
   1.146 +    }
   1.147 +
   1.148 +    public static void main(String... args) throws Exception {
   1.149 +        for (SignatureKind sig1 : SignatureKind.values()) {
   1.150 +            for (ReturnTypeKind rt1 : ReturnTypeKind.values()) {
   1.151 +                for (TypeArgumentKind ta1 : TypeArgumentKind.values()) {
   1.152 +                    if (!ta1.compatibleWith(sig1)) continue;
   1.153 +                    for (SignatureKind sig2 : SignatureKind.values()) {
   1.154 +                        for (ReturnTypeKind rt2 : ReturnTypeKind.values()) {
   1.155 +                            for (TypeArgumentKind ta2 : TypeArgumentKind.values()) {
   1.156 +                                if (!ta2.compatibleWith(sig2)) continue;
   1.157 +                                for (ReturnTypeKind rt3 : ReturnTypeKind.values()) {
   1.158 +                                    for (TypeArgumentKind ta3 : TypeArgumentKind.values()) {
   1.159 +                                        if (!ta3.compatibleWith(SignatureKind.NON_GENERIC))
   1.160 +                                            continue;
   1.161 +                                        for (SourceLevel level : SourceLevel.values()) {
   1.162 +                                            pool.execute(
   1.163 +                                                    new GenericOverrideTest(sig1,
   1.164 +                                                    rt1, ta1, sig2, rt2,
   1.165 +                                                    ta2, rt3, ta3, level));
   1.166 +                                        }
   1.167 +                                    }
   1.168 +                                }
   1.169 +                            }
   1.170 +                        }
   1.171 +                    }
   1.172 +                }
   1.173 +            }
   1.174 +        }
   1.175 +
   1.176 +        checkAfterExec();
   1.177 +    }
   1.178 +
   1.179 +    SignatureKind sig1, sig2;
   1.180 +    ReturnTypeKind rt1, rt2, rt3;
   1.181 +    TypeArgumentKind ta1, ta2, ta3;
   1.182 +    SourceLevel level;
   1.183 +    JavaSource source;
   1.184 +    DiagnosticChecker diagChecker;
   1.185 +
   1.186 +    GenericOverrideTest(SignatureKind sig1, ReturnTypeKind rt1, TypeArgumentKind ta1,
   1.187 +            SignatureKind sig2, ReturnTypeKind rt2, TypeArgumentKind ta2,
   1.188 +            ReturnTypeKind rt3, TypeArgumentKind ta3, SourceLevel level) {
   1.189 +        this.sig1 = sig1;
   1.190 +        this.sig2 = sig2;
   1.191 +        this.rt1 = rt1;
   1.192 +        this.rt2 = rt2;
   1.193 +        this.rt3 = rt3;
   1.194 +        this.ta1 = ta1;
   1.195 +        this.ta2 = ta2;
   1.196 +        this.ta3 = ta3;
   1.197 +        this.level = level;
   1.198 +        this.source = new JavaSource();
   1.199 +        this.diagChecker = new DiagnosticChecker();
   1.200 +    }
   1.201 +
   1.202 +    class JavaSource extends SimpleJavaFileObject {
   1.203 +
   1.204 +        String template = "import java.util.*;\n" +
   1.205 +                          "interface A { #S1 #R1#TA1 m(); }\n" +
   1.206 +                          "interface B { #S2 #R2#TA2 m(); }\n" +
   1.207 +                          "interface AB extends A, B {}\n" +
   1.208 +                          "class Test {\n" +
   1.209 +                          "  void test(AB ab) { #R3#TA3 n = ab.m(); }\n" +
   1.210 +                          "}";
   1.211 +
   1.212 +        String source;
   1.213 +
   1.214 +        public JavaSource() {
   1.215 +            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   1.216 +            source = template.replace("#S1", sig1.paramStr).
   1.217 +                    replace("#S2", sig2.paramStr).
   1.218 +                    replace("#R1", rt1.retStr).
   1.219 +                    replace("#R2", rt2.retStr).
   1.220 +                    replace("#R3", rt3.retStr).
   1.221 +                    replace("#TA1", ta1.typeargStr).
   1.222 +                    replace("#TA2", ta2.typeargStr).
   1.223 +                    replace("#TA3", ta3.typeargStr);
   1.224 +        }
   1.225 +
   1.226 +        @Override
   1.227 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   1.228 +            return source;
   1.229 +        }
   1.230 +    }
   1.231 +
   1.232 +    @Override
   1.233 +    public void run() {
   1.234 +        JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker,
   1.235 +                level.opts != null ? Arrays.asList(level.opts) : null,
   1.236 +                null, Arrays.asList(source));
   1.237 +        try {
   1.238 +            ct.analyze();
   1.239 +        } catch (Throwable ex) {
   1.240 +            throw new AssertionError("Error thrown when compiling the following code:\n" +
   1.241 +                    source.getCharContent(true));
   1.242 +        }
   1.243 +        check();
   1.244 +    }
   1.245 +
   1.246 +    void check() {
   1.247 +        checkCount.incrementAndGet();
   1.248 +
   1.249 +        boolean errorExpected = false;
   1.250 +        int mostSpecific = 0;
   1.251 +
   1.252 +        //first check that either |R1| <: |R2| or |R2| <: |R1|
   1.253 +        if (rt1 != rt2) {
   1.254 +            if (!rt1.moreSpecificThan(rt2) &&
   1.255 +                    !rt2.moreSpecificThan(rt1)) {
   1.256 +                errorExpected = true;
   1.257 +            } else {
   1.258 +                mostSpecific = rt1.moreSpecificThan(rt2) ? 1 : 2;
   1.259 +            }
   1.260 +        }
   1.261 +
   1.262 +        //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
   1.263 +        if (!errorExpected) {
   1.264 +            if (ta1 != ta2) {
   1.265 +                boolean useStrictCheck = ta1.moreSpecificThan(ta2, true) ||
   1.266 +                        ta2.moreSpecificThan(ta1, true);
   1.267 +                if (!ta1.moreSpecificThan(ta2, useStrictCheck) &&
   1.268 +                        !ta2.moreSpecificThan(ta1, useStrictCheck)) {
   1.269 +                    errorExpected = true;
   1.270 +                } else {
   1.271 +                    int mostSpecific2 = ta1.moreSpecificThan(ta2, useStrictCheck) ? 1 : 2;
   1.272 +                    if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
   1.273 +                        errorExpected = mostSpecific == 1 ?
   1.274 +                                ta1 != TypeArgumentKind.NONE :
   1.275 +                                ta2 != TypeArgumentKind.NONE;
   1.276 +                    } else {
   1.277 +                        mostSpecific = mostSpecific2;
   1.278 +                    }
   1.279 +                }
   1.280 +            } else if (mostSpecific == 0) {
   1.281 +                //when no signature is better than the other, an arbitrary choice
   1.282 +                //must be made - javac always picks the second signature
   1.283 +                mostSpecific = 2;
   1.284 +            }
   1.285 +        }
   1.286 +
   1.287 +        //finally, check that most specific return type is compatible with expected type
   1.288 +        if (!errorExpected) {
   1.289 +            ReturnTypeKind msrt = mostSpecific == 1 ? rt1 : rt2;
   1.290 +            TypeArgumentKind msta = mostSpecific == 1 ? ta1 : ta2;
   1.291 +            SignatureKind mssig = mostSpecific == 1 ? sig1 : sig2;
   1.292 +
   1.293 +            if (!msrt.moreSpecificThan(rt3) ||
   1.294 +                    !msta.assignableTo(ta3, mssig, level)) {
   1.295 +                errorExpected = true;
   1.296 +            }
   1.297 +        }
   1.298 +
   1.299 +        if (errorExpected != diagChecker.errorFound) {
   1.300 +            throw new Error("invalid diagnostics for source:\n" +
   1.301 +                source.getCharContent(true) +
   1.302 +                "\nFound error: " + diagChecker.errorFound +
   1.303 +                "\nExpected error: " + errorExpected);
   1.304 +        }
   1.305 +    }
   1.306 +
   1.307 +    static class DiagnosticChecker
   1.308 +        implements javax.tools.DiagnosticListener<JavaFileObject> {
   1.309 +
   1.310 +        boolean errorFound;
   1.311 +
   1.312 +        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   1.313 +            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   1.314 +                errorFound = true;
   1.315 +            }
   1.316 +        }
   1.317 +    }
   1.318 +
   1.319 +}

mercurial