Fri, 21 Aug 2015 13:52:30 +0100
8071291: Compiler crashes trying to cast UnionType to IntersectionClassType
Reviewed-by: mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 07 11:55:35 2015 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 21 13:52:30 2015 +0100 1.3 @@ -421,6 +421,14 @@ 1.4 && (tsym.flags() & COMPOUND) != 0; 1.5 } 1.6 1.7 + public boolean isIntersection() { 1.8 + return false; 1.9 + } 1.10 + 1.11 + public boolean isUnion() { 1.12 + return false; 1.13 + } 1.14 + 1.15 public boolean isInterface() { 1.16 return (tsym.flags() & INTERFACE) != 0; 1.17 } 1.18 @@ -970,6 +978,11 @@ 1.19 } 1.20 1.21 @Override 1.22 + public boolean isUnion() { 1.23 + return true; 1.24 + } 1.25 + 1.26 + @Override 1.27 public TypeKind getKind() { 1.28 return TypeKind.UNION; 1.29 } 1.30 @@ -1003,6 +1016,11 @@ 1.31 return interfaces_field.prepend(supertype_field); 1.32 } 1.33 1.34 + @Override 1.35 + public boolean isIntersection() { 1.36 + return true; 1.37 + } 1.38 + 1.39 public List<Type> getExplicitComponents() { 1.40 return allInterfaces ? 1.41 interfaces_field :
2.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Fri Aug 07 11:55:35 2015 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Aug 21 13:52:30 2015 +0100 2.3 @@ -1539,8 +1539,8 @@ 2.4 } 2.5 } 2.6 2.7 - if (t.isCompound() || s.isCompound()) { 2.8 - return !t.isCompound() ? 2.9 + if (t.isIntersection() || s.isIntersection()) { 2.10 + return !t.isIntersection() ? 2.11 visitIntersectionType((IntersectionClassType)s.unannotatedType(), t, true) : 2.12 visitIntersectionType((IntersectionClassType)t.unannotatedType(), s, false); 2.13 } 2.14 @@ -2255,19 +2255,28 @@ 2.15 } 2.16 // </editor-fold> 2.17 2.18 - // <editor-fold defaultstate="collapsed" desc="makeCompoundType"> 2.19 + // <editor-fold defaultstate="collapsed" desc="makeIntersectionType"> 2.20 /** 2.21 - * Make a compound type from non-empty list of types. The list should be 2.22 - * ordered according to {@link Symbol#precedes(TypeSymbol,Types)}. 2.23 + * Make an intersection type from non-empty list of types. The list should be ordered according to 2.24 + * {@link TypeSymbol#precedes(TypeSymbol, Types)}. Note that this might cause a symbol completion. 2.25 + * Hence, this version of makeIntersectionType may not be called during a classfile read. 2.26 * 2.27 - * @param bounds the types from which the compound type is formed 2.28 - * @param supertype is objectType if all bounds are interfaces, 2.29 - * null otherwise. 2.30 + * @param bounds the types from which the intersection type is formed 2.31 */ 2.32 - public Type makeCompoundType(List<Type> bounds) { 2.33 - return makeCompoundType(bounds, bounds.head.tsym.isInterface()); 2.34 + public IntersectionClassType makeIntersectionType(List<Type> bounds) { 2.35 + return makeIntersectionType(bounds, bounds.head.tsym.isInterface()); 2.36 } 2.37 - public Type makeCompoundType(List<Type> bounds, boolean allInterfaces) { 2.38 + 2.39 + /** 2.40 + * Make an intersection type from non-empty list of types. The list should be ordered according to 2.41 + * {@link TypeSymbol#precedes(TypeSymbol, Types)}. This does not cause symbol completion as 2.42 + * an extra parameter indicates as to whether all bounds are interfaces - in which case the 2.43 + * supertype is implicitly assumed to be 'Object'. 2.44 + * 2.45 + * @param bounds the types from which the intersection type is formed 2.46 + * @param allInterfaces are all bounds interface types? 2.47 + */ 2.48 + public IntersectionClassType makeIntersectionType(List<Type> bounds, boolean allInterfaces) { 2.49 Assert.check(bounds.nonEmpty()); 2.50 Type firstExplicitBound = bounds.head; 2.51 if (allInterfaces) { 2.52 @@ -2280,23 +2289,24 @@ 2.53 : names.empty, 2.54 null, 2.55 syms.noSymbol); 2.56 - bc.type = new IntersectionClassType(bounds, bc, allInterfaces); 2.57 + IntersectionClassType intersectionType = new IntersectionClassType(bounds, bc, allInterfaces); 2.58 + bc.type = intersectionType; 2.59 bc.erasure_field = (bounds.head.hasTag(TYPEVAR)) ? 2.60 syms.objectType : // error condition, recover 2.61 erasure(firstExplicitBound); 2.62 bc.members_field = new Scope(bc); 2.63 - return bc.type; 2.64 + return intersectionType; 2.65 } 2.66 2.67 /** 2.68 - * A convenience wrapper for {@link #makeCompoundType(List)}; the 2.69 + * A convenience wrapper for {@link #makeIntersectionType(List)}; the 2.70 * arguments are converted to a list and passed to the other 2.71 * method. Note that this might cause a symbol completion. 2.72 - * Hence, this version of makeCompoundType may not be called 2.73 + * Hence, this version of makeIntersectionType may not be called 2.74 * during a classfile read. 2.75 */ 2.76 - public Type makeCompoundType(Type bound1, Type bound2) { 2.77 - return makeCompoundType(List.of(bound1, bound2)); 2.78 + public Type makeIntersectionType(Type bound1, Type bound2) { 2.79 + return makeIntersectionType(List.of(bound1, bound2)); 2.80 } 2.81 // </editor-fold> 2.82 2.83 @@ -2436,7 +2446,7 @@ 2.84 private final UnaryVisitor<List<Type>> directSupertypes = new UnaryVisitor<List<Type>>() { 2.85 2.86 public List<Type> visitType(final Type type, final Void ignored) { 2.87 - if (!type.isCompound()) { 2.88 + if (!type.isIntersection()) { 2.89 final Type sup = supertype(type); 2.90 return (sup == Type.noType || sup == type || sup == null) 2.91 ? interfaces(type) 2.92 @@ -2490,30 +2500,32 @@ 2.93 2.94 // <editor-fold defaultstate="collapsed" desc="setBounds"> 2.95 /** 2.96 - * Set the bounds field of the given type variable to reflect a 2.97 - * (possibly multiple) list of bounds. 2.98 - * @param t a type variable 2.99 - * @param bounds the bounds, must be nonempty 2.100 - * @param supertype is objectType if all bounds are interfaces, 2.101 - * null otherwise. 2.102 + * Same as {@link Types#setBounds(TypeVar, List, boolean)}, except that third parameter is computed directly, 2.103 + * as follows: if all all bounds are interface types, the computed supertype is Object,otherwise 2.104 + * the supertype is simply left null (in this case, the supertype is assumed to be the head of 2.105 + * the bound list passed as second argument). Note that this check might cause a symbol completion. 2.106 + * Hence, this version of setBounds may not be called during a classfile read. 2.107 + * 2.108 + * @param t a type variable 2.109 + * @param bounds the bounds, must be nonempty 2.110 */ 2.111 public void setBounds(TypeVar t, List<Type> bounds) { 2.112 setBounds(t, bounds, bounds.head.tsym.isInterface()); 2.113 } 2.114 2.115 /** 2.116 - * Same as {@link #setBounds(Type.TypeVar,List,Type)}, except that 2.117 - * third parameter is computed directly, as follows: if all 2.118 - * all bounds are interface types, the computed supertype is Object, 2.119 - * otherwise the supertype is simply left null (in this case, the supertype 2.120 - * is assumed to be the head of the bound list passed as second argument). 2.121 - * Note that this check might cause a symbol completion. Hence, this version of 2.122 - * setBounds may not be called during a classfile read. 2.123 + * Set the bounds field of the given type variable to reflect a (possibly multiple) list of bounds. 2.124 + * This does not cause symbol completion as an extra parameter indicates as to whether all bounds 2.125 + * are interfaces - in which case the supertype is implicitly assumed to be 'Object'. 2.126 + * 2.127 + * @param t a type variable 2.128 + * @param bounds the bounds, must be nonempty 2.129 + * @param allInterfaces are all bounds interface types? 2.130 */ 2.131 public void setBounds(TypeVar t, List<Type> bounds, boolean allInterfaces) { 2.132 t.bound = bounds.tail.isEmpty() ? 2.133 bounds.head : 2.134 - makeCompoundType(bounds, allInterfaces); 2.135 + makeIntersectionType(bounds, allInterfaces); 2.136 t.rank_field = -1; 2.137 } 2.138 // </editor-fold> 2.139 @@ -3063,7 +3075,7 @@ 2.140 if (st == supertype(t) && is == interfaces(t)) 2.141 return t; 2.142 else 2.143 - return makeCompoundType(is.prepend(st)); 2.144 + return makeIntersectionType(is.prepend(st)); 2.145 } 2.146 } 2.147 2.148 @@ -3566,7 +3578,7 @@ 2.149 else if (compound.tail.isEmpty()) 2.150 return compound.head; 2.151 else 2.152 - return makeCompoundType(compound); 2.153 + return makeIntersectionType(compound); 2.154 } 2.155 2.156 /** 2.157 @@ -3744,8 +3756,8 @@ 2.158 synchronized (this) { 2.159 if (arraySuperType == null) { 2.160 // JLS 10.8: all arrays implement Cloneable and Serializable. 2.161 - arraySuperType = makeCompoundType(List.of(syms.serializableType, 2.162 - syms.cloneableType), true); 2.163 + arraySuperType = makeIntersectionType(List.of(syms.serializableType, 2.164 + syms.cloneableType), true); 2.165 } 2.166 } 2.167 } 2.168 @@ -3811,7 +3823,7 @@ 2.169 return glbFlattened(union(bounds, lowers), errT); 2.170 } 2.171 } 2.172 - return makeCompoundType(bounds); 2.173 + return makeIntersectionType(bounds); 2.174 } 2.175 // </editor-fold> 2.176
3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 07 11:55:35 2015 -0700 3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 21 13:52:30 2015 +0100 3.3 @@ -2434,7 +2434,7 @@ 3.4 3.5 @Override 3.6 public Type visitClassType(ClassType t, DiagnosticPosition pos) { 3.7 - return t.isCompound() ? 3.8 + return t.isIntersection() ? 3.9 visitIntersectionClassType((IntersectionClassType)t, pos) : t; 3.10 } 3.11 3.12 @@ -2465,8 +2465,7 @@ 3.13 } 3.14 supertypes.append(i.tsym.type); 3.15 } 3.16 - IntersectionClassType notionalIntf = 3.17 - (IntersectionClassType)types.makeCompoundType(supertypes.toList()); 3.18 + IntersectionClassType notionalIntf = types.makeIntersectionType(supertypes.toList()); 3.19 notionalIntf.allparams_field = targs.toList(); 3.20 notionalIntf.tsym.flags_field |= INTERFACE; 3.21 return notionalIntf.tsym; 3.22 @@ -4032,7 +4031,7 @@ 3.23 } else if (bounds.length() == 1) { 3.24 return bounds.head.type; 3.25 } else { 3.26 - Type owntype = types.makeCompoundType(TreeInfo.types(bounds)); 3.27 + Type owntype = types.makeIntersectionType(TreeInfo.types(bounds)); 3.28 // ... the variable's bound is a class type flagged COMPOUND 3.29 // (see comment for TypeVar.bound). 3.30 // In this case, generate a class tree that represents the
4.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Aug 07 11:55:35 2015 -0700 4.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Aug 21 13:52:30 2015 +0100 4.3 @@ -1813,7 +1813,7 @@ 4.4 Type t1, 4.5 Type t2) { 4.6 return checkCompatibleAbstracts(pos, t1, t2, 4.7 - types.makeCompoundType(t1, t2)); 4.8 + types.makeIntersectionType(t1, t2)); 4.9 } 4.10 4.11 public boolean checkCompatibleAbstracts(DiagnosticPosition pos,
5.1 --- a/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Aug 07 11:55:35 2015 -0700 5.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Aug 21 13:52:30 2015 +0100 5.3 @@ -373,7 +373,7 @@ 5.4 List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER); 5.5 if (Type.containsAny(upperBounds, vars)) { 5.6 TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); 5.7 - fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null); 5.8 + fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null); 5.9 todo.append(uv); 5.10 uv.inst = fresh_tvar.type; 5.11 } else if (upperBounds.nonEmpty()) {
6.1 --- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Aug 07 11:55:35 2015 -0700 6.2 +++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Aug 21 13:52:30 2015 +0100 6.3 @@ -750,7 +750,7 @@ 6.4 Type originalTarget = tree.type; 6.5 tree.type = erasure(tree.type); 6.6 tree.expr = translate(tree.expr, tree.type); 6.7 - if (originalTarget.isCompound()) { 6.8 + if (originalTarget.isIntersection()) { 6.9 Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget; 6.10 for (Type c : ict.getExplicitComponents()) { 6.11 Type ec = erasure(c);
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/tools/javac/multicatch/8071291/T8071291.java Fri Aug 21 13:52:30 2015 +0100 7.3 @@ -0,0 +1,49 @@ 7.4 +/* 7.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/* 7.28 + * @test 7.29 + * @bug 8071291 7.30 + * @summary Compiler crashes trying to cast UnionType to IntersectionClassType 7.31 + * @compile T8071291.java 7.32 + */ 7.33 + 7.34 +class T8071291 { 7.35 + 7.36 + interface A { } 7.37 + class Exception1 extends Exception implements A { } 7.38 + class Exception2 extends Exception implements A { } 7.39 + 7.40 + void test(boolean cond) { 7.41 + try { 7.42 + if (cond) { 7.43 + throw new Exception1(); 7.44 + } else { 7.45 + throw new Exception2(); 7.46 + } 7.47 + } 7.48 + catch (Exception1|Exception2 x) { 7.49 + if (x instanceof Exception1) { } 7.50 + } 7.51 + } 7.52 +}