mcimadamore@1436: /* vromero@1482: * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. mcimadamore@1436: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mcimadamore@1436: * mcimadamore@1436: * This code is free software; you can redistribute it and/or modify it mcimadamore@1436: * under the terms of the GNU General Public License version 2 only, as mcimadamore@1436: * published by the Free Software Foundation. mcimadamore@1436: * mcimadamore@1436: * This code is distributed in the hope that it will be useful, but WITHOUT mcimadamore@1436: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mcimadamore@1436: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mcimadamore@1436: * version 2 for more details (a copy is included in the LICENSE file that mcimadamore@1436: * accompanied this code). mcimadamore@1436: * mcimadamore@1436: * You should have received a copy of the GNU General Public License version mcimadamore@1436: * 2 along with this work; if not, write to the Free Software Foundation, mcimadamore@1436: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mcimadamore@1436: * mcimadamore@1436: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mcimadamore@1436: * or visit www.oracle.com if you need additional information or have any mcimadamore@1436: * questions. mcimadamore@1436: */ mcimadamore@1436: mcimadamore@1436: /* mcimadamore@1436: * @test vromero@1520: * @bug 8002099 8006694 mcimadamore@1436: * @summary Add support for intersection types in cast expression vromero@1520: * temporarily workaround combo tests are causing time out in several platforms vromero@1482: * @library ../../lib vromero@1482: * @build JavacTestingAbstractThreadedTest vromero@1520: * @run main/othervm/timeout=360 IntersectionTypeCastTest mcimadamore@1436: */ mcimadamore@1436: vromero@1520: // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) vromero@1520: // see JDK-8006746 vromero@1520: mcimadamore@1436: import java.net.URI; mcimadamore@1436: import java.util.Arrays; mcimadamore@1436: import javax.tools.Diagnostic; mcimadamore@1436: import javax.tools.JavaCompiler; mcimadamore@1436: import javax.tools.JavaFileObject; mcimadamore@1436: import javax.tools.SimpleJavaFileObject; mcimadamore@1436: import javax.tools.ToolProvider; mcimadamore@1436: vromero@1482: import com.sun.source.util.JavacTask; vromero@1482: import com.sun.tools.javac.util.List; vromero@1482: import com.sun.tools.javac.util.ListBuffer; mcimadamore@1436: vromero@1482: public class IntersectionTypeCastTest vromero@1482: extends JavacTestingAbstractThreadedTest vromero@1482: implements Runnable { mcimadamore@1436: mcimadamore@1436: interface Type { mcimadamore@1436: boolean subtypeOf(Type that); mcimadamore@1436: String asString(); mcimadamore@1436: boolean isClass(); mcimadamore@1436: boolean isInterface(); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: enum InterfaceKind implements Type { mcimadamore@1436: A("interface A { }\n", "A", null), mcimadamore@1436: B("interface B { }\n", "B", null), mcimadamore@1436: C("interface C extends A { }\n", "C", A); mcimadamore@1436: mcimadamore@1436: String declStr; mcimadamore@1436: String typeStr; mcimadamore@1436: InterfaceKind superInterface; mcimadamore@1436: vromero@1482: InterfaceKind(String declStr, String typeStr, vromero@1482: InterfaceKind superInterface) { mcimadamore@1436: this.declStr = declStr; mcimadamore@1436: this.typeStr = typeStr; mcimadamore@1436: this.superInterface = superInterface; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean subtypeOf(Type that) { vromero@1482: return this == that || superInterface == that || vromero@1482: that == ClassKind.OBJECT; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public String asString() { mcimadamore@1436: return typeStr; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean isClass() { mcimadamore@1436: return false; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean isInterface() { mcimadamore@1436: return true; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: enum ClassKind implements Type { mcimadamore@1436: OBJECT(null, "Object"), vromero@1482: CA("#M class CA implements A { }\n", "CA", vromero@1482: InterfaceKind.A), vromero@1482: CB("#M class CB implements B { }\n", "CB", vromero@1482: InterfaceKind.B), vromero@1482: CAB("#M class CAB implements A, B { }\n", "CAB", vromero@1482: InterfaceKind.A, InterfaceKind.B), vromero@1482: CC("#M class CC implements C { }\n", "CC", vromero@1482: InterfaceKind.C, InterfaceKind.A), vromero@1482: CCA("#M class CCA implements C, A { }\n", "CCA", vromero@1482: InterfaceKind.C, InterfaceKind.A), vromero@1482: CCB("#M class CCB implements C, B { }\n", "CCB", vromero@1482: InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), vromero@1482: CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", vromero@1482: InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); mcimadamore@1436: mcimadamore@1436: String declTemplate; mcimadamore@1436: String typeStr; mcimadamore@1436: List superInterfaces; mcimadamore@1436: vromero@1482: ClassKind(String declTemplate, String typeStr, vromero@1482: InterfaceKind... superInterfaces) { mcimadamore@1436: this.declTemplate = declTemplate; mcimadamore@1436: this.typeStr = typeStr; mcimadamore@1436: this.superInterfaces = List.from(superInterfaces); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: String getDecl(ModifierKind mod) { mcimadamore@1436: return declTemplate != null ? mcimadamore@1436: declTemplate.replaceAll("#M", mod.modStr) : mcimadamore@1436: ""; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean subtypeOf(Type that) { vromero@1482: return this == that || superInterfaces.contains(that) || vromero@1482: that == OBJECT; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public String asString() { mcimadamore@1436: return typeStr; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean isClass() { mcimadamore@1436: return true; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public boolean isInterface() { mcimadamore@1436: return false; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: enum ModifierKind { mcimadamore@1436: NONE(""), mcimadamore@1436: FINAL("final"); mcimadamore@1436: mcimadamore@1436: String modStr; mcimadamore@1436: mcimadamore@1436: ModifierKind(String modStr) { mcimadamore@1436: this.modStr = modStr; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: enum CastKind { mcimadamore@1436: CLASS("(#C)", 0), mcimadamore@1436: INTERFACE("(#I0)", 1), mcimadamore@1436: INTERSECTION2("(#C & #I0)", 1), mcimadamore@1436: INTERSECTION3("(#C & #I0 & #I1)", 2); mcimadamore@1436: //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); mcimadamore@1436: mcimadamore@1436: String castTemplate; mcimadamore@1436: int interfaceBounds; mcimadamore@1436: mcimadamore@1436: CastKind(String castTemplate, int interfaceBounds) { mcimadamore@1436: this.castTemplate = castTemplate; mcimadamore@1436: this.interfaceBounds = interfaceBounds; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: static class CastInfo { mcimadamore@1436: CastKind kind; mcimadamore@1436: Type[] types; mcimadamore@1436: mcimadamore@1436: CastInfo(CastKind kind, Type... types) { mcimadamore@1436: this.kind = kind; mcimadamore@1436: this.types = types; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: String getCast() { vromero@1482: String temp = kind.castTemplate.replaceAll("#C", vromero@1482: types[0].asString()); mcimadamore@1436: for (int i = 0; i < kind.interfaceBounds ; i++) { vromero@1482: temp = temp.replace(String.format("#I%d", i), vromero@1482: types[i + 1].asString()); mcimadamore@1436: } mcimadamore@1436: return temp; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: boolean hasDuplicateTypes() { mcimadamore@1436: for (int i = 0 ; i < types.length ; i++) { mcimadamore@1436: for (int j = 0 ; j < types.length ; j++) { mcimadamore@1436: if (i != j && types[i] == types[j]) { mcimadamore@1436: return true; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: return false; mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: boolean compatibleWith(ModifierKind mod, CastInfo that) { mcimadamore@1436: for (Type t1 : types) { mcimadamore@1436: for (Type t2 : that.types) { mcimadamore@1436: boolean compat = mcimadamore@1436: t1.subtypeOf(t2) || mcimadamore@1436: t2.subtypeOf(t1) || mcimadamore@1436: (t1.isInterface() && t2.isInterface()) || //side-cast (1) vromero@1482: (mod == ModifierKind.NONE && vromero@1482: (t1.isInterface() != t2.isInterface())); //side-cast (2) mcimadamore@1436: if (!compat) return false; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: return true; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: public static void main(String... args) throws Exception { mcimadamore@1436: for (ModifierKind mod : ModifierKind.values()) { mcimadamore@1436: for (CastInfo cast1 : allCastInfo()) { mcimadamore@1436: for (CastInfo cast2 : allCastInfo()) { vromero@1482: pool.execute( vromero@1482: new IntersectionTypeCastTest(mod, cast1, cast2)); mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } vromero@1482: checkAfterExec(); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: static List allCastInfo() { mcimadamore@1436: ListBuffer buf = ListBuffer.lb(); mcimadamore@1436: for (CastKind kind : CastKind.values()) { mcimadamore@1436: for (ClassKind clazz : ClassKind.values()) { mcimadamore@1436: if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { mcimadamore@1436: continue; mcimadamore@1436: } else if (kind.interfaceBounds == 0) { mcimadamore@1436: buf.append(new CastInfo(kind, clazz)); mcimadamore@1436: continue; mcimadamore@1436: } else { mcimadamore@1436: for (InterfaceKind intf1 : InterfaceKind.values()) { mcimadamore@1436: if (kind.interfaceBounds == 1) { mcimadamore@1436: buf.append(new CastInfo(kind, clazz, intf1)); mcimadamore@1436: continue; mcimadamore@1436: } else { mcimadamore@1436: for (InterfaceKind intf2 : InterfaceKind.values()) { mcimadamore@1436: if (kind.interfaceBounds == 2) { vromero@1482: buf.append( vromero@1482: new CastInfo(kind, clazz, intf1, intf2)); mcimadamore@1436: continue; mcimadamore@1436: } else { mcimadamore@1436: for (InterfaceKind intf3 : InterfaceKind.values()) { vromero@1482: buf.append( vromero@1482: new CastInfo(kind, clazz, intf1, vromero@1482: intf2, intf3)); mcimadamore@1436: continue; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: return buf.toList(); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: ModifierKind mod; mcimadamore@1436: CastInfo cast1, cast2; mcimadamore@1436: JavaSource source; mcimadamore@1436: DiagnosticChecker diagChecker; mcimadamore@1436: mcimadamore@1436: IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { mcimadamore@1436: this.mod = mod; mcimadamore@1436: this.cast1 = cast1; mcimadamore@1436: this.cast2 = cast2; mcimadamore@1436: this.source = new JavaSource(); mcimadamore@1436: this.diagChecker = new DiagnosticChecker(); mcimadamore@1436: } mcimadamore@1436: vromero@1482: @Override vromero@1482: public void run() { vromero@1482: final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); vromero@1482: vromero@1482: JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, mcimadamore@1511: null, null, Arrays.asList(source)); vromero@1482: try { vromero@1482: ct.analyze(); vromero@1482: } catch (Throwable ex) { vromero@1482: throw new AssertionError("Error thrown when compiling the following code:\n" + vromero@1482: source.getCharContent(true)); vromero@1482: } vromero@1482: check(); vromero@1482: } vromero@1482: mcimadamore@1436: class JavaSource extends SimpleJavaFileObject { mcimadamore@1436: mcimadamore@1436: String bodyTemplate = "class Test {\n" + mcimadamore@1436: " void test() {\n" + mcimadamore@1436: " Object o = #C1#C2null;\n" + mcimadamore@1436: " } }"; mcimadamore@1436: mcimadamore@1436: String source = ""; mcimadamore@1436: mcimadamore@1436: public JavaSource() { mcimadamore@1436: super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); mcimadamore@1436: for (ClassKind ck : ClassKind.values()) { mcimadamore@1436: source += ck.getDecl(mod); mcimadamore@1436: } mcimadamore@1436: for (InterfaceKind ik : InterfaceKind.values()) { mcimadamore@1436: source += ik.declStr; mcimadamore@1436: } vromero@1482: source += bodyTemplate.replaceAll("#C1", cast1.getCast()). vromero@1482: replaceAll("#C2", cast2.getCast()); mcimadamore@1436: } mcimadamore@1436: mcimadamore@1436: @Override mcimadamore@1436: public CharSequence getCharContent(boolean ignoreEncodingErrors) { mcimadamore@1436: return source; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: vromero@1482: void check() { vromero@1482: checkCount.incrementAndGet(); mcimadamore@1436: vromero@1482: boolean errorExpected = cast1.hasDuplicateTypes() || vromero@1482: cast2.hasDuplicateTypes(); mcimadamore@1436: mcimadamore@1436: errorExpected |= !cast2.compatibleWith(mod, cast1); mcimadamore@1436: mcimadamore@1436: if (errorExpected != diagChecker.errorFound) { mcimadamore@1436: throw new Error("invalid diagnostics for source:\n" + mcimadamore@1436: source.getCharContent(true) + mcimadamore@1436: "\nFound error: " + diagChecker.errorFound + mcimadamore@1436: "\nExpected error: " + errorExpected); mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: vromero@1482: static class DiagnosticChecker vromero@1482: implements javax.tools.DiagnosticListener { mcimadamore@1436: mcimadamore@1436: boolean errorFound; mcimadamore@1436: mcimadamore@1436: public void report(Diagnostic diagnostic) { mcimadamore@1436: if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { mcimadamore@1436: errorFound = true; mcimadamore@1436: } mcimadamore@1436: } mcimadamore@1436: } vromero@1482: mcimadamore@1436: }