Fri, 30 Nov 2012 15:14:48 +0000
8002099: Add support for intersection types in cast expression
Summary: Add parser and type-checking support for intersection types in cast expressions
Reviewed-by: jjg
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java Fri Nov 30 15:14:48 2012 +0000 1.3 @@ -0,0 +1,39 @@ 1.4 +/* 1.5 + * Copyright (c) 2012, 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. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.source.tree; 1.30 + 1.31 +import java.util.List; 1.32 + 1.33 +/** 1.34 + * A tree node for an intersection type in a cast expression. 1.35 + * 1.36 + * @author Maurizio Cimadamore 1.37 + * 1.38 + * @since 1.8 1.39 + */ 1.40 +public interface IntersectionTypeTree extends Tree { 1.41 + List<? extends Tree> getBounds(); 1.42 +}
2.1 --- a/src/share/classes/com/sun/source/tree/Tree.java Fri Nov 30 15:14:36 2012 +0000 2.2 +++ b/src/share/classes/com/sun/source/tree/Tree.java Fri Nov 30 15:14:48 2012 +0000 2.3 @@ -247,6 +247,11 @@ 2.4 UNION_TYPE(UnionTypeTree.class), 2.5 2.6 /** 2.7 + * Used for instances of {@link IntersectionTypeTree}. 2.8 + */ 2.9 + INTERSECTION_TYPE(IntersectionTypeTree.class), 2.10 + 2.11 + /** 2.12 * Used for instances of {@link TypeCastTree}. 2.13 */ 2.14 TYPE_CAST(TypeCastTree.class),
3.1 --- a/src/share/classes/com/sun/source/tree/TreeVisitor.java Fri Nov 30 15:14:36 2012 +0000 3.2 +++ b/src/share/classes/com/sun/source/tree/TreeVisitor.java Fri Nov 30 15:14:48 2012 +0000 3.3 @@ -98,6 +98,7 @@ 3.4 R visitTry(TryTree node, P p); 3.5 R visitParameterizedType(ParameterizedTypeTree node, P p); 3.6 R visitUnionType(UnionTypeTree node, P p); 3.7 + R visitIntersectionType(IntersectionTypeTree node, P p); 3.8 R visitArrayType(ArrayTypeTree node, P p); 3.9 R visitTypeCast(TypeCastTree node, P p); 3.10 R visitPrimitiveType(PrimitiveTypeTree node, P p);
4.1 --- a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Fri Nov 30 15:14:36 2012 +0000 4.2 +++ b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Fri Nov 30 15:14:48 2012 +0000 4.3 @@ -240,6 +240,10 @@ 4.4 return defaultAction(node, p); 4.5 } 4.6 4.7 + public R visitIntersectionType(IntersectionTypeTree node, P p) { 4.8 + return defaultAction(node, p); 4.9 + } 4.10 + 4.11 public R visitTypeParameter(TypeParameterTree node, P p) { 4.12 return defaultAction(node, p); 4.13 }
5.1 --- a/src/share/classes/com/sun/source/util/TreeScanner.java Fri Nov 30 15:14:36 2012 +0000 5.2 +++ b/src/share/classes/com/sun/source/util/TreeScanner.java Fri Nov 30 15:14:48 2012 +0000 5.3 @@ -371,6 +371,10 @@ 5.4 return scan(node.getTypeAlternatives(), p); 5.5 } 5.6 5.7 + public R visitIntersectionType(IntersectionTypeTree node, P p) { 5.8 + return scan(node.getBounds(), p); 5.9 + } 5.10 + 5.11 public R visitTypeParameter(TypeParameterTree node, P p) { 5.12 R r = scan(node.getBounds(), p); 5.13 return r;
6.1 --- a/src/share/classes/com/sun/tools/javac/code/Source.java Fri Nov 30 15:14:36 2012 +0000 6.2 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java Fri Nov 30 15:14:48 2012 +0000 6.3 @@ -215,6 +215,9 @@ 6.4 public boolean allowRepeatedAnnotations() { 6.5 return compareTo(JDK1_8) >= 0; 6.6 } 6.7 + public boolean allowIntersectionTypesInCast() { 6.8 + return compareTo(JDK1_8) >= 0; 6.9 + } 6.10 public static SourceVersion toSourceVersion(Source source) { 6.11 switch(source) { 6.12 case JDK1_2:
7.1 --- a/src/share/classes/com/sun/tools/javac/code/Type.java Fri Nov 30 15:14:36 2012 +0000 7.2 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Fri Nov 30 15:14:48 2012 +0000 7.3 @@ -839,6 +839,49 @@ 7.4 } 7.5 } 7.6 7.7 + // a clone of a ClassType that knows about the bounds of an intersection type. 7.8 + public static class IntersectionClassType extends ClassType implements IntersectionType { 7.9 + 7.10 + public boolean allInterfaces; 7.11 + 7.12 + public enum IntersectionKind { 7.13 + EXPLICIT, 7.14 + IMPLICT; 7.15 + } 7.16 + 7.17 + public IntersectionKind intersectionKind; 7.18 + 7.19 + public IntersectionClassType(List<Type> bounds, ClassSymbol csym, boolean allInterfaces) { 7.20 + super(Type.noType, List.<Type>nil(), csym); 7.21 + this.allInterfaces = allInterfaces; 7.22 + Assert.check((csym.flags() & COMPOUND) != 0); 7.23 + supertype_field = bounds.head; 7.24 + interfaces_field = bounds.tail; 7.25 + Assert.check(supertype_field.tsym.completer != null || 7.26 + !supertype_field.isInterface(), supertype_field); 7.27 + } 7.28 + 7.29 + public java.util.List<? extends TypeMirror> getBounds() { 7.30 + return Collections.unmodifiableList(getComponents()); 7.31 + } 7.32 + 7.33 + public List<Type> getComponents() { 7.34 + return interfaces_field.prepend(supertype_field); 7.35 + } 7.36 + 7.37 + @Override 7.38 + public TypeKind getKind() { 7.39 + return TypeKind.INTERSECTION; 7.40 + } 7.41 + 7.42 + @Override 7.43 + public <R, P> R accept(TypeVisitor<R, P> v, P p) { 7.44 + return intersectionKind == IntersectionKind.EXPLICIT ? 7.45 + v.visitIntersection(this, p) : 7.46 + v.visitDeclared(this, p); 7.47 + } 7.48 + } 7.49 + 7.50 public static class ArrayType extends Type 7.51 implements javax.lang.model.type.ArrayType { 7.52
8.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Fri Nov 30 15:14:36 2012 +0000 8.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Nov 30 15:14:48 2012 +0000 8.3 @@ -389,28 +389,6 @@ 8.4 } 8.5 8.6 /** 8.7 - * Scope filter used to skip methods that should be ignored during 8.8 - * function interface conversion (such as methods overridden by 8.9 - * j.l.Object) 8.10 - */ 8.11 - class DescriptorFilter implements Filter<Symbol> { 8.12 - 8.13 - TypeSymbol origin; 8.14 - 8.15 - DescriptorFilter(TypeSymbol origin) { 8.16 - this.origin = origin; 8.17 - } 8.18 - 8.19 - @Override 8.20 - public boolean accepts(Symbol sym) { 8.21 - return sym.kind == Kinds.MTH && 8.22 - (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT && 8.23 - !overridesObjectMethod(origin, sym) && 8.24 - (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0; 8.25 - } 8.26 - }; 8.27 - 8.28 - /** 8.29 * Compute the function descriptor associated with a given functional interface 8.30 */ 8.31 public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError { 8.32 @@ -577,6 +555,85 @@ 8.33 } 8.34 // </editor-fold> 8.35 8.36 + /** 8.37 + * Scope filter used to skip methods that should be ignored (such as methods 8.38 + * overridden by j.l.Object) during function interface conversion/marker interface checks 8.39 + */ 8.40 + class DescriptorFilter implements Filter<Symbol> { 8.41 + 8.42 + TypeSymbol origin; 8.43 + 8.44 + DescriptorFilter(TypeSymbol origin) { 8.45 + this.origin = origin; 8.46 + } 8.47 + 8.48 + @Override 8.49 + public boolean accepts(Symbol sym) { 8.50 + return sym.kind == Kinds.MTH && 8.51 + (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT && 8.52 + !overridesObjectMethod(origin, sym) && 8.53 + (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0; 8.54 + } 8.55 + }; 8.56 + 8.57 + // <editor-fold defaultstate="collapsed" desc="isMarker"> 8.58 + 8.59 + /** 8.60 + * A cache that keeps track of marker interfaces 8.61 + */ 8.62 + class MarkerCache { 8.63 + 8.64 + private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>(); 8.65 + 8.66 + class Entry { 8.67 + final boolean isMarkerIntf; 8.68 + final int prevMark; 8.69 + 8.70 + public Entry(boolean isMarkerIntf, 8.71 + int prevMark) { 8.72 + this.isMarkerIntf = isMarkerIntf; 8.73 + this.prevMark = prevMark; 8.74 + } 8.75 + 8.76 + boolean matches(int mark) { 8.77 + return this.prevMark == mark; 8.78 + } 8.79 + } 8.80 + 8.81 + boolean get(TypeSymbol origin) throws FunctionDescriptorLookupError { 8.82 + Entry e = _map.get(origin); 8.83 + CompoundScope members = membersClosure(origin.type, false); 8.84 + if (e == null || 8.85 + !e.matches(members.getMark())) { 8.86 + boolean isMarkerIntf = isMarkerInterfaceInternal(origin, members); 8.87 + _map.put(origin, new Entry(isMarkerIntf, members.getMark())); 8.88 + return isMarkerIntf; 8.89 + } 8.90 + else { 8.91 + return e.isMarkerIntf; 8.92 + } 8.93 + } 8.94 + 8.95 + /** 8.96 + * Is given symbol a marker interface 8.97 + */ 8.98 + public boolean isMarkerInterfaceInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError { 8.99 + return !origin.isInterface() ? 8.100 + false : 8.101 + !membersCache.getElements(new DescriptorFilter(origin)).iterator().hasNext(); 8.102 + } 8.103 + } 8.104 + 8.105 + private MarkerCache markerCache = new MarkerCache(); 8.106 + 8.107 + /** 8.108 + * Is given type a marker interface? 8.109 + */ 8.110 + public boolean isMarkerInterface(Type site) { 8.111 + return markerCache.get(site.tsym); 8.112 + } 8.113 + // </editor-fold> 8.114 + 8.115 // <editor-fold defaultstate="collapsed" desc="isSubtype"> 8.116 /** 8.117 * Is t an unchecked subtype of s? 8.118 @@ -1955,45 +2012,28 @@ 8.119 * @param supertype is objectType if all bounds are interfaces, 8.120 * null otherwise. 8.121 */ 8.122 - public Type makeCompoundType(List<Type> bounds, 8.123 - Type supertype) { 8.124 + public Type makeCompoundType(List<Type> bounds) { 8.125 + return makeCompoundType(bounds, bounds.head.tsym.isInterface()); 8.126 + } 8.127 + public Type makeCompoundType(List<Type> bounds, boolean allInterfaces) { 8.128 + Assert.check(bounds.nonEmpty()); 8.129 + Type firstExplicitBound = bounds.head; 8.130 + if (allInterfaces) { 8.131 + bounds = bounds.prepend(syms.objectType); 8.132 + } 8.133 ClassSymbol bc = 8.134 new ClassSymbol(ABSTRACT|PUBLIC|SYNTHETIC|COMPOUND|ACYCLIC, 8.135 Type.moreInfo 8.136 ? names.fromString(bounds.toString()) 8.137 : names.empty, 8.138 + null, 8.139 syms.noSymbol); 8.140 - if (bounds.head.tag == TYPEVAR) 8.141 - // error condition, recover 8.142 - bc.erasure_field = syms.objectType; 8.143 - else 8.144 - bc.erasure_field = erasure(bounds.head); 8.145 - bc.members_field = new Scope(bc); 8.146 - ClassType bt = (ClassType)bc.type; 8.147 - bt.allparams_field = List.nil(); 8.148 - if (supertype != null) { 8.149 - bt.supertype_field = supertype; 8.150 - bt.interfaces_field = bounds; 8.151 - } else { 8.152 - bt.supertype_field = bounds.head; 8.153 - bt.interfaces_field = bounds.tail; 8.154 - } 8.155 - Assert.check(bt.supertype_field.tsym.completer != null 8.156 - || !bt.supertype_field.isInterface(), 8.157 - bt.supertype_field); 8.158 - return bt; 8.159 - } 8.160 - 8.161 - /** 8.162 - * Same as {@link #makeCompoundType(List,Type)}, except that the 8.163 - * second parameter is computed directly. Note that this might 8.164 - * cause a symbol completion. Hence, this version of 8.165 - * makeCompoundType may not be called during a classfile read. 8.166 - */ 8.167 - public Type makeCompoundType(List<Type> bounds) { 8.168 - Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ? 8.169 - supertype(bounds.head) : null; 8.170 - return makeCompoundType(bounds, supertype); 8.171 + bc.type = new IntersectionClassType(bounds, bc, allInterfaces); 8.172 + bc.erasure_field = (bounds.head.tag == TYPEVAR) ? 8.173 + syms.objectType : // error condition, recover 8.174 + erasure(firstExplicitBound); 8.175 + bc.members_field = new Scope(bc); 8.176 + return bc.type; 8.177 } 8.178 8.179 /** 8.180 @@ -2183,12 +2223,8 @@ 8.181 * @param supertype is objectType if all bounds are interfaces, 8.182 * null otherwise. 8.183 */ 8.184 - public void setBounds(TypeVar t, List<Type> bounds, Type supertype) { 8.185 - if (bounds.tail.isEmpty()) 8.186 - t.bound = bounds.head; 8.187 - else 8.188 - t.bound = makeCompoundType(bounds, supertype); 8.189 - t.rank_field = -1; 8.190 + public void setBounds(TypeVar t, List<Type> bounds) { 8.191 + setBounds(t, bounds, bounds.head.tsym.isInterface()); 8.192 } 8.193 8.194 /** 8.195 @@ -2200,10 +2236,10 @@ 8.196 * Note that this check might cause a symbol completion. Hence, this version of 8.197 * setBounds may not be called during a classfile read. 8.198 */ 8.199 - public void setBounds(TypeVar t, List<Type> bounds) { 8.200 - Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ? 8.201 - syms.objectType : null; 8.202 - setBounds(t, bounds, supertype); 8.203 + public void setBounds(TypeVar t, List<Type> bounds, boolean allInterfaces) { 8.204 + t.bound = bounds.tail.isEmpty() ? 8.205 + bounds.head : 8.206 + makeCompoundType(bounds, allInterfaces); 8.207 t.rank_field = -1; 8.208 } 8.209 // </editor-fold> 8.210 @@ -2213,7 +2249,7 @@ 8.211 * Return list of bounds of the given type variable. 8.212 */ 8.213 public List<Type> getBounds(TypeVar t) { 8.214 - if (t.bound.hasTag(NONE)) 8.215 + if (t.bound.hasTag(NONE)) 8.216 return List.nil(); 8.217 else if (t.bound.isErroneous() || !t.bound.isCompound()) 8.218 return List.of(t.bound); 8.219 @@ -3312,8 +3348,7 @@ 8.220 if (arraySuperType == null) { 8.221 // JLS 10.8: all arrays implement Cloneable and Serializable. 8.222 arraySuperType = makeCompoundType(List.of(syms.serializableType, 8.223 - syms.cloneableType), 8.224 - syms.objectType); 8.225 + syms.cloneableType), true); 8.226 } 8.227 } 8.228 }
9.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 30 15:14:36 2012 +0000 9.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Nov 30 15:14:48 2012 +0000 9.3 @@ -716,21 +716,8 @@ 9.4 } 9.5 a.tsym.flags_field &= ~UNATTRIBUTED; 9.6 } 9.7 - for (JCTypeParameter tvar : typarams) 9.8 + for (JCTypeParameter tvar : typarams) { 9.9 chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type); 9.10 - attribStats(typarams, env); 9.11 - } 9.12 - 9.13 - void attribBounds(List<JCTypeParameter> typarams) { 9.14 - for (JCTypeParameter typaram : typarams) { 9.15 - Type bound = typaram.type.getUpperBound(); 9.16 - if (bound != null && bound.tsym instanceof ClassSymbol) { 9.17 - ClassSymbol c = (ClassSymbol)bound.tsym; 9.18 - if ((c.flags_field & COMPOUND) != 0) { 9.19 - Assert.check((c.flags_field & UNATTRIBUTED) != 0, c); 9.20 - attribClass(typaram.pos(), c); 9.21 - } 9.22 - } 9.23 } 9.24 } 9.25 9.26 @@ -892,7 +879,12 @@ 9.27 deferredLintHandler.flush(tree.pos()); 9.28 chk.checkDeprecatedAnnotation(tree.pos(), m); 9.29 9.30 - attribBounds(tree.typarams); 9.31 + // Create a new environment with local scope 9.32 + // for attributing the method. 9.33 + Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env); 9.34 + localEnv.info.lint = lint; 9.35 + 9.36 + attribStats(tree.typarams, localEnv); 9.37 9.38 // If we override any other methods, check that we do so properly. 9.39 // JLS ??? 9.40 @@ -903,12 +895,6 @@ 9.41 } 9.42 chk.checkOverride(tree, m); 9.43 9.44 - // Create a new environment with local scope 9.45 - // for attributing the method. 9.46 - Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env); 9.47 - 9.48 - localEnv.info.lint = lint; 9.49 - 9.50 if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) { 9.51 log.error(tree, "default.overrides.object.member", m.name, Kinds.kindName(m.location()), m.location()); 9.52 } 9.53 @@ -2196,7 +2182,7 @@ 9.54 Type target; 9.55 Type lambdaType; 9.56 if (pt() != Type.recoveryType) { 9.57 - target = infer.instantiateFunctionalInterface(that, pt(), explicitParamTypes, resultInfo.checkContext); 9.58 + target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), explicitParamTypes, resultInfo.checkContext); 9.59 lambdaType = types.findDescriptorType(target); 9.60 chk.checkFunctionalInterface(that, target); 9.61 } else { 9.62 @@ -2294,6 +2280,26 @@ 9.63 } 9.64 } 9.65 } 9.66 + 9.67 + private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) { 9.68 + Type pt = resultInfo.pt; 9.69 + if (pt != Type.recoveryType && pt.isCompound()) { 9.70 + IntersectionClassType ict = (IntersectionClassType)pt; 9.71 + List<Type> bounds = ict.allInterfaces ? 9.72 + ict.getComponents().tail : 9.73 + ict.getComponents(); 9.74 + types.findDescriptorType(bounds.head); //propagate exception outwards! 9.75 + for (Type bound : bounds.tail) { 9.76 + if (!types.isMarkerInterface(bound)) { 9.77 + resultInfo.checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound)); 9.78 + } 9.79 + } 9.80 + //for now (translation doesn't support intersection types) 9.81 + return bounds.head; 9.82 + } else { 9.83 + return pt; 9.84 + } 9.85 + } 9.86 //where 9.87 private Type fallbackDescriptorType(JCExpression tree) { 9.88 switch (tree.getTag()) { 9.89 @@ -2466,7 +2472,7 @@ 9.90 Type target; 9.91 Type desc; 9.92 if (pt() != Type.recoveryType) { 9.93 - target = infer.instantiateFunctionalInterface(that, pt(), null, resultInfo.checkContext); 9.94 + target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), null, resultInfo.checkContext); 9.95 desc = types.findDescriptorType(target); 9.96 chk.checkFunctionalInterface(that, target); 9.97 } else { 9.98 @@ -3575,63 +3581,79 @@ 9.99 tree.type = result = t; 9.100 } 9.101 9.102 - public void visitTypeParameter(JCTypeParameter tree) { 9.103 - TypeVar a = (TypeVar)tree.type; 9.104 + public void visitTypeIntersection(JCTypeIntersection tree) { 9.105 + attribTypes(tree.bounds, env); 9.106 + tree.type = result = checkIntersection(tree, tree.bounds); 9.107 + } 9.108 + 9.109 + public void visitTypeParameter(JCTypeParameter tree) { 9.110 + TypeVar typeVar = (TypeVar)tree.type; 9.111 + if (!typeVar.bound.isErroneous()) { 9.112 + //fixup type-parameter bound computed in 'attribTypeVariables' 9.113 + typeVar.bound = checkIntersection(tree, tree.bounds); 9.114 + } 9.115 + } 9.116 + 9.117 + Type checkIntersection(JCTree tree, List<JCExpression> bounds) { 9.118 Set<Type> boundSet = new HashSet<Type>(); 9.119 - if (a.bound.isErroneous()) 9.120 - return; 9.121 - List<Type> bs = types.getBounds(a); 9.122 - if (tree.bounds.nonEmpty()) { 9.123 + if (bounds.nonEmpty()) { 9.124 // accept class or interface or typevar as first bound. 9.125 - Type b = checkBase(bs.head, tree.bounds.head, env, false, false, false); 9.126 - boundSet.add(types.erasure(b)); 9.127 - if (b.isErroneous()) { 9.128 - a.bound = b; 9.129 + bounds.head.type = checkBase(bounds.head.type, bounds.head, env, false, false, false); 9.130 + boundSet.add(types.erasure(bounds.head.type)); 9.131 + if (bounds.head.type.isErroneous()) { 9.132 + return bounds.head.type; 9.133 } 9.134 - else if (b.hasTag(TYPEVAR)) { 9.135 + else if (bounds.head.type.hasTag(TYPEVAR)) { 9.136 // if first bound was a typevar, do not accept further bounds. 9.137 - if (tree.bounds.tail.nonEmpty()) { 9.138 - log.error(tree.bounds.tail.head.pos(), 9.139 + if (bounds.tail.nonEmpty()) { 9.140 + log.error(bounds.tail.head.pos(), 9.141 "type.var.may.not.be.followed.by.other.bounds"); 9.142 - tree.bounds = List.of(tree.bounds.head); 9.143 - a.bound = bs.head; 9.144 + return bounds.head.type; 9.145 } 9.146 } else { 9.147 // if first bound was a class or interface, accept only interfaces 9.148 // as further bounds. 9.149 - for (JCExpression bound : tree.bounds.tail) { 9.150 - bs = bs.tail; 9.151 - Type i = checkBase(bs.head, bound, env, false, true, false); 9.152 - if (i.isErroneous()) 9.153 - a.bound = i; 9.154 - else if (i.hasTag(CLASS)) 9.155 - chk.checkNotRepeated(bound.pos(), types.erasure(i), boundSet); 9.156 + for (JCExpression bound : bounds.tail) { 9.157 + bound.type = checkBase(bound.type, bound, env, false, true, false); 9.158 + if (bound.type.isErroneous()) { 9.159 + bounds = List.of(bound); 9.160 + } 9.161 + else if (bound.type.hasTag(CLASS)) { 9.162 + chk.checkNotRepeated(bound.pos(), types.erasure(bound.type), boundSet); 9.163 + } 9.164 } 9.165 } 9.166 } 9.167 - bs = types.getBounds(a); 9.168 - 9.169 - // in case of multiple bounds ... 9.170 - if (bs.length() > 1) { 9.171 + 9.172 + if (bounds.length() == 0) { 9.173 + return syms.objectType; 9.174 + } else if (bounds.length() == 1) { 9.175 + return bounds.head.type; 9.176 + } else { 9.177 + Type owntype = types.makeCompoundType(TreeInfo.types(bounds)); 9.178 + if (tree.hasTag(TYPEINTERSECTION)) { 9.179 + ((IntersectionClassType)owntype).intersectionKind = 9.180 + IntersectionClassType.IntersectionKind.EXPLICIT; 9.181 + } 9.182 // ... the variable's bound is a class type flagged COMPOUND 9.183 // (see comment for TypeVar.bound). 9.184 // In this case, generate a class tree that represents the 9.185 // bound class, ... 9.186 JCExpression extending; 9.187 List<JCExpression> implementing; 9.188 - if ((bs.head.tsym.flags() & INTERFACE) == 0) { 9.189 - extending = tree.bounds.head; 9.190 - implementing = tree.bounds.tail; 9.191 + if (!bounds.head.type.isInterface()) { 9.192 + extending = bounds.head; 9.193 + implementing = bounds.tail; 9.194 } else { 9.195 extending = null; 9.196 - implementing = tree.bounds; 9.197 + implementing = bounds; 9.198 } 9.199 - JCClassDecl cd = make.at(tree.pos).ClassDef( 9.200 + JCClassDecl cd = make.at(tree).ClassDef( 9.201 make.Modifiers(PUBLIC | ABSTRACT), 9.202 - tree.name, List.<JCTypeParameter>nil(), 9.203 + names.empty, List.<JCTypeParameter>nil(), 9.204 extending, implementing, List.<JCTree>nil()); 9.205 9.206 - ClassSymbol c = (ClassSymbol)a.getUpperBound().tsym; 9.207 + ClassSymbol c = (ClassSymbol)owntype.tsym; 9.208 Assert.check((c.flags() & COMPOUND) != 0); 9.209 cd.sym = c; 9.210 c.sourcefile = env.toplevel.sourcefile; 9.211 @@ -3640,10 +3662,11 @@ 9.212 c.flags_field |= UNATTRIBUTED; 9.213 Env<AttrContext> cenv = enter.classEnv(cd, env); 9.214 enter.typeEnvs.put(c, cenv); 9.215 + attribClass(c); 9.216 + return owntype; 9.217 } 9.218 } 9.219 9.220 - 9.221 public void visitWildcard(JCWildcard tree) { 9.222 //- System.err.println("visitWildcard("+tree+");");//DEBUG 9.223 Type type = (tree.kind.kind == BoundKind.UNBOUND) 9.224 @@ -3797,7 +3820,7 @@ 9.225 chk.validateAnnotations(tree.mods.annotations, c); 9.226 9.227 // Validate type parameters, supertype and interfaces. 9.228 - attribBounds(tree.typarams); 9.229 + attribStats(tree.typarams, env); 9.230 if (!c.isAnonymous()) { 9.231 //already checked if anonymous 9.232 chk.validate(tree.typarams, env);
10.1 --- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Nov 30 15:14:36 2012 +0000 10.2 +++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Nov 30 15:14:48 2012 +0000 10.3 @@ -551,6 +551,7 @@ 10.4 tree.body = translate(tree.body, null); 10.5 //save non-erased target 10.6 tree.targetType = tree.type; 10.7 + Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!"); 10.8 tree.type = erasure(tree.type); 10.9 result = tree; 10.10 } 10.11 @@ -786,6 +787,7 @@ 10.12 tree.expr = translate(tree.expr, null); 10.13 //save non-erased target 10.14 tree.targetType = tree.type; 10.15 + Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!"); 10.16 tree.type = erasure(tree.type); 10.17 result = tree; 10.18 } 10.19 @@ -803,6 +805,12 @@ 10.20 result = clazz; 10.21 } 10.22 10.23 + public void visitTypeIntersection(JCTypeIntersection tree) { 10.24 + tree.bounds = translate(tree.bounds, null); 10.25 + tree.type = erasure(tree.type); 10.26 + result = tree; 10.27 + } 10.28 + 10.29 /************************************************************************** 10.30 * utility methods 10.31 *************************************************************************/
11.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Nov 30 15:14:36 2012 +0000 11.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Nov 30 15:14:48 2012 +0000 11.3 @@ -846,17 +846,17 @@ 11.4 tvar = (TypeVar)findTypeVar(name); 11.5 } 11.6 List<Type> bounds = List.nil(); 11.7 - Type st = null; 11.8 + boolean allInterfaces = false; 11.9 if (signature[sigp] == ':' && signature[sigp+1] == ':') { 11.10 sigp++; 11.11 - st = syms.objectType; 11.12 + allInterfaces = true; 11.13 } 11.14 while (signature[sigp] == ':') { 11.15 sigp++; 11.16 bounds = bounds.prepend(sigToType()); 11.17 } 11.18 if (!sigEnterPhase) { 11.19 - types.setBounds(tvar, bounds.reverse(), st); 11.20 + types.setBounds(tvar, bounds.reverse(), allInterfaces); 11.21 } 11.22 return tvar; 11.23 }
12.1 --- a/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Fri Nov 30 15:14:36 2012 +0000 12.2 +++ b/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Fri Nov 30 15:14:48 2012 +0000 12.3 @@ -74,6 +74,7 @@ 12.4 public Element asElement(TypeMirror t) { 12.5 switch (t.getKind()) { 12.6 case DECLARED: 12.7 + case INTERSECTION: 12.8 case ERROR: 12.9 case TYPEVAR: 12.10 Type type = cast(Type.class, t);
13.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:36 2012 +0000 13.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 30 15:14:48 2012 +0000 13.3 @@ -124,6 +124,9 @@ 13.4 this.allowLambda = source.allowLambda(); 13.5 this.allowMethodReferences = source.allowMethodReferences(); 13.6 this.allowDefaultMethods = source.allowDefaultMethods(); 13.7 + this.allowIntersectionTypesInCast = 13.8 + source.allowIntersectionTypesInCast() && 13.9 + fac.options.isSet("allowIntersectionTypes"); 13.10 this.keepDocComments = keepDocComments; 13.11 docComments = newDocCommentTable(keepDocComments, fac); 13.12 this.keepLineMap = keepLineMap; 13.13 @@ -197,6 +200,10 @@ 13.14 */ 13.15 boolean allowDefaultMethods; 13.16 13.17 + /** Switch: should we allow intersection types in cast? 13.18 + */ 13.19 + boolean allowIntersectionTypesInCast; 13.20 + 13.21 /** Switch: should we keep docComments? 13.22 */ 13.23 boolean keepDocComments; 13.24 @@ -239,22 +246,38 @@ 13.25 } 13.26 13.27 protected boolean peekToken(TokenKind tk) { 13.28 - return S.token(1).kind == tk; 13.29 + return peekToken(0, tk); 13.30 + } 13.31 + 13.32 + protected boolean peekToken(int lookahead, TokenKind tk) { 13.33 + return S.token(lookahead + 1).kind == tk; 13.34 } 13.35 13.36 protected boolean peekToken(TokenKind tk1, TokenKind tk2) { 13.37 - return S.token(1).kind == tk1 && 13.38 - S.token(2).kind == tk2; 13.39 + return peekToken(0, tk1, tk2); 13.40 + } 13.41 + 13.42 + protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) { 13.43 + return S.token(lookahead + 1).kind == tk1 && 13.44 + S.token(lookahead + 2).kind == tk2; 13.45 } 13.46 13.47 protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) { 13.48 - return S.token(1).kind == tk1 && 13.49 - S.token(2).kind == tk2 && 13.50 - S.token(3).kind == tk3; 13.51 + return peekToken(0, tk1, tk2, tk3); 13.52 + } 13.53 + 13.54 + protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) { 13.55 + return S.token(lookahead + 1).kind == tk1 && 13.56 + S.token(lookahead + 2).kind == tk2 && 13.57 + S.token(lookahead + 3).kind == tk3; 13.58 } 13.59 13.60 protected boolean peekToken(TokenKind... kinds) { 13.61 - for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) { 13.62 + return peekToken(0, kinds); 13.63 + } 13.64 + 13.65 + protected boolean peekToken(int lookahead, TokenKind... kinds) { 13.66 + for (; lookahead < kinds.length ; lookahead++) { 13.67 if (S.token(lookahead + 1).kind != kinds[lookahead]) { 13.68 return false; 13.69 } 13.70 @@ -966,102 +989,40 @@ 13.71 break; 13.72 case LPAREN: 13.73 if (typeArgs == null && (mode & EXPR) != 0) { 13.74 - if (peekToken(MONKEYS_AT) || 13.75 - peekToken(FINAL) || 13.76 - peekToken(RPAREN) || 13.77 - peekToken(IDENTIFIER, COMMA) || 13.78 - peekToken(IDENTIFIER, RPAREN, ARROW)) { 13.79 - //implicit n-ary lambda 13.80 - t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos); 13.81 - break; 13.82 - } else { 13.83 - nextToken(); 13.84 - mode = EXPR | TYPE | NOPARAMS; 13.85 - t = term3(); 13.86 - if ((mode & TYPE) != 0 && token.kind == LT) { 13.87 - // Could be a cast to a parameterized type 13.88 - JCTree.Tag op = JCTree.Tag.LT; 13.89 - int pos1 = token.pos; 13.90 - nextToken(); 13.91 - mode &= (EXPR | TYPE); 13.92 - mode |= TYPEARG; 13.93 - JCExpression t1 = term3(); 13.94 - if ((mode & TYPE) != 0 && 13.95 - (token.kind == COMMA || token.kind == GT)) { 13.96 - mode = TYPE; 13.97 - ListBuffer<JCExpression> args = new ListBuffer<JCExpression>(); 13.98 - args.append(t1); 13.99 - while (token.kind == COMMA) { 13.100 - nextToken(); 13.101 - args.append(typeArgument()); 13.102 - } 13.103 - accept(GT); 13.104 - t = toP(F.at(pos1).TypeApply(t, args.toList())); 13.105 - checkGenerics(); 13.106 - mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type 13.107 - t = term3Rest(t, typeArgs); 13.108 - if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) { 13.109 - //explicit lambda (w/ generic type) 13.110 - mode = EXPR; 13.111 - JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); 13.112 - if (token.kind == ELLIPSIS) { 13.113 - mods.flags = Flags.VARARGS; 13.114 - t = to(F.at(token.pos).TypeArray(t)); 13.115 - nextToken(); 13.116 - } 13.117 - t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos); 13.118 - break; 13.119 - } 13.120 - } else if ((mode & EXPR) != 0) { 13.121 - mode = EXPR; 13.122 - JCExpression e = term2Rest(t1, TreeInfo.shiftPrec); 13.123 - t = F.at(pos1).Binary(op, t, e); 13.124 - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); 13.125 - } else { 13.126 - accept(GT); 13.127 - } 13.128 - } else if ((mode & TYPE) != 0 && 13.129 - (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) { 13.130 - //explicit lambda (w/ non-generic type) 13.131 + ParensResult pres = analyzeParens(); 13.132 + switch (pres) { 13.133 + case CAST: 13.134 + accept(LPAREN); 13.135 + mode = TYPE; 13.136 + int pos1 = pos; 13.137 + List<JCExpression> targets = List.of(t = term3()); 13.138 + while (token.kind == AMP) { 13.139 + checkIntersectionTypesInCast(); 13.140 + accept(AMP); 13.141 + targets = targets.prepend(term3()); 13.142 + } 13.143 + if (targets.length() > 1) { 13.144 + t = toP(F.at(pos1).TypeIntersection(targets.reverse())); 13.145 + } 13.146 + accept(RPAREN); 13.147 + mode = EXPR; 13.148 + JCExpression t1 = term3(); 13.149 + return F.at(pos).TypeCast(t, t1); 13.150 + case IMPLICIT_LAMBDA: 13.151 + case EXPLICIT_LAMBDA: 13.152 + t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos); 13.153 + break; 13.154 + default: //PARENS 13.155 + accept(LPAREN); 13.156 mode = EXPR; 13.157 - JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER); 13.158 - if (token.kind == ELLIPSIS) { 13.159 - mods.flags = Flags.VARARGS; 13.160 - t = to(F.at(token.pos).TypeArray(t)); 13.161 - nextToken(); 13.162 - } 13.163 - t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos); 13.164 + t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec))); 13.165 + accept(RPAREN); 13.166 + t = toP(F.at(pos).Parens(t)); 13.167 break; 13.168 - } else { 13.169 - t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec))); 13.170 - } 13.171 - } 13.172 - 13.173 - accept(RPAREN); 13.174 - lastmode = mode; 13.175 - mode = EXPR; 13.176 - if ((lastmode & EXPR) == 0) { 13.177 - JCExpression t1 = term3(); 13.178 - return F.at(pos).TypeCast(t, t1); 13.179 - } else if ((lastmode & TYPE) != 0) { 13.180 - switch (token.kind) { 13.181 - /*case PLUSPLUS: case SUBSUB: */ 13.182 - case BANG: case TILDE: 13.183 - case LPAREN: case THIS: case SUPER: 13.184 - case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: 13.185 - case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: 13.186 - case TRUE: case FALSE: case NULL: 13.187 - case NEW: case IDENTIFIER: case ASSERT: case ENUM: 13.188 - case BYTE: case SHORT: case CHAR: case INT: 13.189 - case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: 13.190 - JCExpression t1 = term3(); 13.191 - return F.at(pos).TypeCast(t, t1); 13.192 - } 13.193 } 13.194 } else { 13.195 return illegal(); 13.196 } 13.197 - t = toP(F.at(pos).Parens(t)); 13.198 break; 13.199 case THIS: 13.200 if ((mode & EXPR) != 0) { 13.201 @@ -1346,6 +1307,138 @@ 13.202 } 13.203 } 13.204 13.205 + /** 13.206 + * If we see an identifier followed by a '<' it could be an unbound 13.207 + * method reference or a binary expression. To disambiguate, look for a 13.208 + * matching '>' and see if the subsequent terminal is either '.' or '#'. 13.209 + */ 13.210 + @SuppressWarnings("fallthrough") 13.211 + ParensResult analyzeParens() { 13.212 + int depth = 0; 13.213 + boolean type = false; 13.214 + for (int lookahead = 0 ; ; lookahead++) { 13.215 + TokenKind tk = S.token(lookahead).kind; 13.216 + switch (tk) { 13.217 + case EXTENDS: case SUPER: case COMMA: 13.218 + type = true; 13.219 + case QUES: case DOT: case AMP: 13.220 + //skip 13.221 + break; 13.222 + case BYTE: case SHORT: case INT: case LONG: case FLOAT: 13.223 + case DOUBLE: case BOOLEAN: case CHAR: 13.224 + if (peekToken(lookahead, RPAREN)) { 13.225 + //Type, ')' -> cast 13.226 + return ParensResult.CAST; 13.227 + } else if (peekToken(lookahead, IDENTIFIER)) { 13.228 + //Type, 'Identifier -> explicit lambda 13.229 + return ParensResult.EXPLICIT_LAMBDA; 13.230 + } 13.231 + break; 13.232 + case LPAREN: 13.233 + if (lookahead != 0) { 13.234 + // '(' in a non-starting position -> parens 13.235 + return ParensResult.PARENS; 13.236 + } else if (peekToken(lookahead, RPAREN)) { 13.237 + // '(', ')' -> explicit lambda 13.238 + return ParensResult.EXPLICIT_LAMBDA; 13.239 + } 13.240 + break; 13.241 + case RPAREN: 13.242 + // if we have seen something that looks like a type, 13.243 + // then it's a cast expression 13.244 + if (type) return ParensResult.CAST; 13.245 + // otherwise, disambiguate cast vs. parenthesized expression 13.246 + // based on subsequent token. 13.247 + switch (S.token(lookahead + 1).kind) { 13.248 + /*case PLUSPLUS: case SUBSUB: */ 13.249 + case BANG: case TILDE: 13.250 + case LPAREN: case THIS: case SUPER: 13.251 + case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: 13.252 + case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: 13.253 + case TRUE: case FALSE: case NULL: 13.254 + case NEW: case IDENTIFIER: case ASSERT: case ENUM: 13.255 + case BYTE: case SHORT: case CHAR: case INT: 13.256 + case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: 13.257 + return ParensResult.CAST; 13.258 + default: 13.259 + return ParensResult.PARENS; 13.260 + } 13.261 + case IDENTIFIER: 13.262 + if (peekToken(lookahead, IDENTIFIER)) { 13.263 + // Identifier, Identifier -> explicit lambda 13.264 + return ParensResult.EXPLICIT_LAMBDA; 13.265 + } else if (peekToken(lookahead, RPAREN, ARROW)) { 13.266 + // Identifier, ')' '->' -> implicit lambda 13.267 + return ParensResult.IMPLICIT_LAMBDA; 13.268 + } 13.269 + break; 13.270 + case FINAL: 13.271 + case ELLIPSIS: 13.272 + case MONKEYS_AT: 13.273 + //those can only appear in explicit lambdas 13.274 + return ParensResult.EXPLICIT_LAMBDA; 13.275 + case LBRACKET: 13.276 + if (peekToken(lookahead, RBRACKET, IDENTIFIER)) { 13.277 + // '[', ']', Identifier -> explicit lambda 13.278 + return ParensResult.EXPLICIT_LAMBDA; 13.279 + } else if (peekToken(lookahead, RBRACKET, RPAREN) || 13.280 + peekToken(lookahead, RBRACKET, AMP)) { 13.281 + // '[', ']', ')' -> cast 13.282 + // '[', ']', '&' -> cast (intersection type) 13.283 + return ParensResult.CAST; 13.284 + } else if (peekToken(lookahead, RBRACKET)) { 13.285 + //consume the ']' and skip 13.286 + type = true; 13.287 + lookahead++; 13.288 + break; 13.289 + } else { 13.290 + return ParensResult.PARENS; 13.291 + } 13.292 + case LT: 13.293 + depth++; break; 13.294 + case GTGTGT: 13.295 + depth--; 13.296 + case GTGT: 13.297 + depth--; 13.298 + case GT: 13.299 + depth--; 13.300 + if (depth == 0) { 13.301 + if (peekToken(lookahead, RPAREN) || 13.302 + peekToken(lookahead, AMP)) { 13.303 + // '>', ')' -> cast 13.304 + // '>', '&' -> cast 13.305 + return ParensResult.CAST; 13.306 + } else if (peekToken(lookahead, IDENTIFIER, COMMA) || 13.307 + peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) || 13.308 + peekToken(lookahead, ELLIPSIS)) { 13.309 + // '>', Identifier, ',' -> explicit lambda 13.310 + // '>', Identifier, ')', '->' -> explicit lambda 13.311 + // '>', '...' -> explicit lambda 13.312 + return ParensResult.EXPLICIT_LAMBDA; 13.313 + } 13.314 + //it looks a type, but could still be (i) a cast to generic type, 13.315 + //(ii) an unbound method reference or (iii) an explicit lambda 13.316 + type = true; 13.317 + break; 13.318 + } else if (depth < 0) { 13.319 + //unbalanced '<', '>' - not a generic type 13.320 + return ParensResult.PARENS; 13.321 + } 13.322 + break; 13.323 + default: 13.324 + //this includes EOF 13.325 + return ParensResult.PARENS; 13.326 + } 13.327 + } 13.328 + } 13.329 + 13.330 + enum ParensResult { 13.331 + CAST, 13.332 + EXPLICIT_LAMBDA, 13.333 + IMPLICIT_LAMBDA, 13.334 + PARENS; 13.335 + } 13.336 + 13.337 JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) { 13.338 ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>(); 13.339 params.append(firstParam); 13.340 @@ -3386,6 +3479,12 @@ 13.341 allowDefaultMethods = true; 13.342 } 13.343 } 13.344 + void checkIntersectionTypesInCast() { 13.345 + if (!allowIntersectionTypesInCast) { 13.346 + log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name); 13.347 + allowIntersectionTypesInCast = true; 13.348 + } 13.349 + } 13.350 13.351 /* 13.352 * a functional source tree and end position mappings
14.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 30 15:14:36 2012 +0000 14.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 30 15:14:48 2012 +0000 14.3 @@ -207,6 +207,10 @@ 14.4 compiler.misc.no.suitable.functional.intf.inst=\ 14.5 cannot infer functional interface descriptor for {0} 14.6 14.7 +# 0: type 14.8 +compiler.misc.secondary.bound.must.be.marker.intf=\ 14.9 + secondary bound {0} must be a marker interface 14.10 + 14.11 # 0: symbol kind, 1: message segment 14.12 compiler.err.invalid.mref=\ 14.13 invalid {0} reference; {1} 14.14 @@ -2203,6 +2207,11 @@ 14.15 default methods are not supported in -source {0}\n\ 14.16 (use -source 8 or higher to enable default methods) 14.17 14.18 +# 0: string 14.19 +compiler.err.intersection.types.in.cast.not.supported.in.source=\ 14.20 + intersection types in cast are not supported in -source {0}\n\ 14.21 + (use -source 8 or higher to enable default methods) 14.22 + 14.23 ######################################## 14.24 # Diagnostics for verbose resolution 14.25 # used by Resolve (debug only)
15.1 --- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Nov 30 15:14:36 2012 +0000 15.2 +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Nov 30 15:14:48 2012 +0000 15.3 @@ -254,6 +254,10 @@ 15.4 */ 15.5 TYPEUNION, 15.6 15.7 + /** Intersection types, of type TypeIntersection 15.8 + */ 15.9 + TYPEINTERSECTION, 15.10 + 15.11 /** Formal type parameters, of type TypeParameter. 15.12 */ 15.13 TYPEPARAMETER, 15.14 @@ -2062,6 +2066,34 @@ 15.15 } 15.16 15.17 /** 15.18 + * An intersection type, T1 & T2 & ... Tn (used in cast expressions) 15.19 + */ 15.20 + public static class JCTypeIntersection extends JCExpression implements IntersectionTypeTree { 15.21 + 15.22 + public List<JCExpression> bounds; 15.23 + 15.24 + protected JCTypeIntersection(List<JCExpression> bounds) { 15.25 + this.bounds = bounds; 15.26 + } 15.27 + @Override 15.28 + public void accept(Visitor v) { v.visitTypeIntersection(this); } 15.29 + 15.30 + public Kind getKind() { return Kind.INTERSECTION_TYPE; } 15.31 + 15.32 + public List<JCExpression> getBounds() { 15.33 + return bounds; 15.34 + } 15.35 + @Override 15.36 + public <R,D> R accept(TreeVisitor<R,D> v, D d) { 15.37 + return v.visitIntersectionType(this, d); 15.38 + } 15.39 + @Override 15.40 + public Tag getTag() { 15.41 + return TYPEINTERSECTION; 15.42 + } 15.43 + } 15.44 + 15.45 + /** 15.46 * A formal class parameter. 15.47 */ 15.48 public static class JCTypeParameter extends JCTree implements TypeParameterTree { 15.49 @@ -2383,6 +2415,7 @@ 15.50 public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); } 15.51 public void visitTypeApply(JCTypeApply that) { visitTree(that); } 15.52 public void visitTypeUnion(JCTypeUnion that) { visitTree(that); } 15.53 + public void visitTypeIntersection(JCTypeIntersection that) { visitTree(that); } 15.54 public void visitTypeParameter(JCTypeParameter that) { visitTree(that); } 15.55 public void visitWildcard(JCWildcard that) { visitTree(that); } 15.56 public void visitTypeBoundKind(TypeBoundKind that) { visitTree(that); }
16.1 --- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java Fri Nov 30 15:14:36 2012 +0000 16.2 +++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java Fri Nov 30 15:14:48 2012 +0000 16.3 @@ -1249,6 +1249,14 @@ 16.4 } 16.5 } 16.6 16.7 + public void visitTypeIntersection(JCTypeIntersection tree) { 16.8 + try { 16.9 + printExprs(tree.bounds, " & "); 16.10 + } catch (IOException e) { 16.11 + throw new UncheckedIOException(e); 16.12 + } 16.13 + } 16.14 + 16.15 public void visitTypeParameter(JCTypeParameter tree) { 16.16 try { 16.17 print(tree.name);
17.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Nov 30 15:14:36 2012 +0000 17.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Fri Nov 30 15:14:48 2012 +0000 17.3 @@ -358,6 +358,12 @@ 17.4 return M.at(t.pos).TypeUnion(components); 17.5 } 17.6 17.7 + public JCTree visitIntersectionType(IntersectionTypeTree node, P p) { 17.8 + JCTypeIntersection t = (JCTypeIntersection) node; 17.9 + List<JCExpression> bounds = copy(t.bounds, p); 17.10 + return M.at(t.pos).TypeIntersection(bounds); 17.11 + } 17.12 + 17.13 public JCTree visitArrayType(ArrayTypeTree node, P p) { 17.14 JCArrayTypeTree t = (JCArrayTypeTree) node; 17.15 JCExpression elemtype = copy(t.elemtype, p);
18.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Nov 30 15:14:36 2012 +0000 18.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Nov 30 15:14:48 2012 +0000 18.3 @@ -456,6 +456,12 @@ 18.4 return tree; 18.5 } 18.6 18.7 + public JCTypeIntersection TypeIntersection(List<JCExpression> components) { 18.8 + JCTypeIntersection tree = new JCTypeIntersection(components); 18.9 + tree.pos = pos; 18.10 + return tree; 18.11 + } 18.12 + 18.13 public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) { 18.14 JCTypeParameter tree = new JCTypeParameter(name, bounds); 18.15 tree.pos = pos;
19.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Fri Nov 30 15:14:36 2012 +0000 19.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Fri Nov 30 15:14:48 2012 +0000 19.3 @@ -286,6 +286,10 @@ 19.4 scan(tree.alternatives); 19.5 } 19.6 19.7 + public void visitTypeIntersection(JCTypeIntersection tree) { 19.8 + scan(tree.bounds); 19.9 + } 19.10 + 19.11 public void visitTypeParameter(JCTypeParameter tree) { 19.12 scan(tree.bounds); 19.13 }
20.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Fri Nov 30 15:14:36 2012 +0000 20.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Fri Nov 30 15:14:48 2012 +0000 20.3 @@ -379,6 +379,11 @@ 20.4 result = tree; 20.5 } 20.6 20.7 + public void visitTypeIntersection(JCTypeIntersection tree) { 20.8 + tree.bounds = translate(tree.bounds); 20.9 + result = tree; 20.10 + } 20.11 + 20.12 public void visitTypeParameter(JCTypeParameter tree) { 20.13 tree.bounds = translate(tree.bounds); 20.14 result = tree;
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/src/share/classes/javax/lang/model/type/IntersectionType.java Fri Nov 30 15:14:48 2012 +0000 21.3 @@ -0,0 +1,47 @@ 21.4 +/* 21.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 21.7 + * 21.8 + * This code is free software; you can redistribute it and/or modify it 21.9 + * under the terms of the GNU General Public License version 2 only, as 21.10 + * published by the Free Software Foundation. Oracle designates this 21.11 + * particular file as subject to the "Classpath" exception as provided 21.12 + * by Oracle in the LICENSE file that accompanied this code. 21.13 + * 21.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 21.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21.17 + * version 2 for more details (a copy is included in the LICENSE file that 21.18 + * accompanied this code). 21.19 + * 21.20 + * You should have received a copy of the GNU General Public License version 21.21 + * 2 along with this work; if not, write to the Free Software Foundation, 21.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21.23 + * 21.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21.25 + * or visit www.oracle.com if you need additional information or have any 21.26 + * questions. 21.27 + */ 21.28 + 21.29 +package javax.lang.model.type; 21.30 + 21.31 +import java.util.List; 21.32 + 21.33 +/** 21.34 + * Represents an intersection type. 21.35 + * 21.36 + * As of the {@link javax.lang.model.SourceVersion#RELEASE_8 21.37 + * RELEASE_8} source version, intersection types can appear as the target type 21.38 + * of a cast expression. 21.39 + * 21.40 + * @since 1.8 21.41 + */ 21.42 +public interface IntersectionType extends TypeMirror { 21.43 + 21.44 + /** 21.45 + * Return the bounds comprising this intersection type. 21.46 + * 21.47 + * @return the bounds of this intersection types. 21.48 + */ 21.49 + List<? extends TypeMirror> getBounds(); 21.50 +}
22.1 --- a/src/share/classes/javax/lang/model/type/TypeKind.java Fri Nov 30 15:14:36 2012 +0000 22.2 +++ b/src/share/classes/javax/lang/model/type/TypeKind.java Fri Nov 30 15:14:48 2012 +0000 22.3 @@ -144,7 +144,14 @@ 22.4 * 22.5 * @since 1.7 22.6 */ 22.7 - UNION; 22.8 + UNION, 22.9 + 22.10 + /** 22.11 + * An intersection type. 22.12 + * 22.13 + * @since 1.8 22.14 + */ 22.15 + INTERSECTION; 22.16 22.17 /** 22.18 * Returns {@code true} if this kind corresponds to a primitive
23.1 --- a/src/share/classes/javax/lang/model/type/TypeVisitor.java Fri Nov 30 15:14:36 2012 +0000 23.2 +++ b/src/share/classes/javax/lang/model/type/TypeVisitor.java Fri Nov 30 15:14:48 2012 +0000 23.3 @@ -172,4 +172,14 @@ 23.4 * @since 1.7 23.5 */ 23.6 R visitUnion(UnionType t, P p); 23.7 + 23.8 + /** 23.9 + * Visits an intersection type. 23.10 + * 23.11 + * @param t the type to visit 23.12 + * @param p a visitor-specified parameter 23.13 + * @return a visitor-specified result 23.14 + * @since 1.8 23.15 + */ 23.16 + R visitIntersection(IntersectionType t, P p); 23.17 }
24.1 --- a/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java Fri Nov 30 15:14:36 2012 +0000 24.2 +++ b/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java Fri Nov 30 15:14:48 2012 +0000 24.3 @@ -111,6 +111,20 @@ 24.4 } 24.5 24.6 /** 24.7 + * Visits an {@code IntersectionType} element by calling {@code 24.8 + * visitUnknown}. 24.9 + 24.10 + * @param t {@inheritDoc} 24.11 + * @param p {@inheritDoc} 24.12 + * @return the result of {@code visitUnknown} 24.13 + * 24.14 + * @since 1.8 24.15 + */ 24.16 + public R visitIntersection(IntersectionType t, P p) { 24.17 + return visitUnknown(t, p); 24.18 + } 24.19 + 24.20 + /** 24.21 * {@inheritDoc} 24.22 * 24.23 * <p> The default implementation of this method in {@code
25.1 --- a/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java Fri Nov 30 15:14:36 2012 +0000 25.2 +++ b/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java Fri Nov 30 15:14:48 2012 +0000 25.3 @@ -66,4 +66,13 @@ 25.4 protected AbstractTypeVisitor8() { 25.5 super(); 25.6 } 25.7 + 25.8 + /** 25.9 + * Visits an {@code IntersectionType} in a manner defined by a subclass. 25.10 + * 25.11 + * @param t {@inheritDoc} 25.12 + * @param p {@inheritDoc} 25.13 + * @return the result of the visit as defined by a subclass 25.14 + */ 25.15 + public abstract R visitIntersection(IntersectionType t, P p); 25.16 }
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Fri Nov 30 15:14:48 2012 +0000 26.3 @@ -0,0 +1,330 @@ 26.4 +/* 26.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 26.7 + * 26.8 + * This code is free software; you can redistribute it and/or modify it 26.9 + * under the terms of the GNU General Public License version 2 only, as 26.10 + * published by the Free Software Foundation. 26.11 + * 26.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 26.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 26.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26.15 + * version 2 for more details (a copy is included in the LICENSE file that 26.16 + * accompanied this code). 26.17 + * 26.18 + * You should have received a copy of the GNU General Public License version 26.19 + * 2 along with this work; if not, write to the Free Software Foundation, 26.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26.21 + * 26.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 26.23 + * or visit www.oracle.com if you need additional information or have any 26.24 + * questions. 26.25 + */ 26.26 + 26.27 +/* 26.28 + * @test 26.29 + * @bug 8002099 26.30 + * @summary Add support for intersection types in cast expression 26.31 + */ 26.32 + 26.33 +import com.sun.source.util.JavacTask; 26.34 +import com.sun.tools.javac.util.List; 26.35 +import com.sun.tools.javac.util.ListBuffer; 26.36 +import java.net.URI; 26.37 +import java.util.Arrays; 26.38 +import javax.tools.Diagnostic; 26.39 +import javax.tools.JavaCompiler; 26.40 +import javax.tools.JavaFileObject; 26.41 +import javax.tools.SimpleJavaFileObject; 26.42 +import javax.tools.StandardJavaFileManager; 26.43 +import javax.tools.ToolProvider; 26.44 + 26.45 +public class IntersectionTypeCastTest { 26.46 + 26.47 + static int checkCount = 0; 26.48 + 26.49 + interface Type { 26.50 + boolean subtypeOf(Type that); 26.51 + String asString(); 26.52 + boolean isClass(); 26.53 + boolean isInterface(); 26.54 + } 26.55 + 26.56 + enum InterfaceKind implements Type { 26.57 + A("interface A { }\n", "A", null), 26.58 + B("interface B { }\n", "B", null), 26.59 + C("interface C extends A { }\n", "C", A); 26.60 + 26.61 + String declStr; 26.62 + String typeStr; 26.63 + InterfaceKind superInterface; 26.64 + 26.65 + InterfaceKind(String declStr, String typeStr, InterfaceKind superInterface) { 26.66 + this.declStr = declStr; 26.67 + this.typeStr = typeStr; 26.68 + this.superInterface = superInterface; 26.69 + } 26.70 + 26.71 + @Override 26.72 + public boolean subtypeOf(Type that) { 26.73 + return this == that || superInterface == that || that == ClassKind.OBJECT; 26.74 + } 26.75 + 26.76 + @Override 26.77 + public String asString() { 26.78 + return typeStr; 26.79 + } 26.80 + 26.81 + @Override 26.82 + public boolean isClass() { 26.83 + return false; 26.84 + } 26.85 + 26.86 + @Override 26.87 + public boolean isInterface() { 26.88 + return true; 26.89 + } 26.90 + } 26.91 + 26.92 + enum ClassKind implements Type { 26.93 + OBJECT(null, "Object"), 26.94 + CA("#M class CA implements A { }\n", "CA", InterfaceKind.A), 26.95 + CB("#M class CB implements B { }\n", "CB", InterfaceKind.B), 26.96 + CAB("#M class CAB implements A, B { }\n", "CAB", InterfaceKind.A, InterfaceKind.B), 26.97 + CC("#M class CC implements C { }\n", "CC", InterfaceKind.C, InterfaceKind.A), 26.98 + CCA("#M class CCA implements C, A { }\n", "CCA", InterfaceKind.C, InterfaceKind.A), 26.99 + CCB("#M class CCB implements C, B { }\n", "CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B), 26.100 + CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B); 26.101 + 26.102 + String declTemplate; 26.103 + String typeStr; 26.104 + List<InterfaceKind> superInterfaces; 26.105 + 26.106 + ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) { 26.107 + this.declTemplate = declTemplate; 26.108 + this.typeStr = typeStr; 26.109 + this.superInterfaces = List.from(superInterfaces); 26.110 + } 26.111 + 26.112 + String getDecl(ModifierKind mod) { 26.113 + return declTemplate != null ? 26.114 + declTemplate.replaceAll("#M", mod.modStr) : 26.115 + ""; 26.116 + } 26.117 + 26.118 + @Override 26.119 + public boolean subtypeOf(Type that) { 26.120 + return this == that || superInterfaces.contains(that) || that == OBJECT; 26.121 + } 26.122 + 26.123 + @Override 26.124 + public String asString() { 26.125 + return typeStr; 26.126 + } 26.127 + 26.128 + @Override 26.129 + public boolean isClass() { 26.130 + return true; 26.131 + } 26.132 + 26.133 + @Override 26.134 + public boolean isInterface() { 26.135 + return false; 26.136 + } 26.137 + } 26.138 + 26.139 + enum ModifierKind { 26.140 + NONE(""), 26.141 + FINAL("final"); 26.142 + 26.143 + String modStr; 26.144 + 26.145 + ModifierKind(String modStr) { 26.146 + this.modStr = modStr; 26.147 + } 26.148 + } 26.149 + 26.150 + enum CastKind { 26.151 + CLASS("(#C)", 0), 26.152 + INTERFACE("(#I0)", 1), 26.153 + INTERSECTION2("(#C & #I0)", 1), 26.154 + INTERSECTION3("(#C & #I0 & #I1)", 2); 26.155 + //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3); 26.156 + 26.157 + String castTemplate; 26.158 + int interfaceBounds; 26.159 + 26.160 + CastKind(String castTemplate, int interfaceBounds) { 26.161 + this.castTemplate = castTemplate; 26.162 + this.interfaceBounds = interfaceBounds; 26.163 + } 26.164 + } 26.165 + 26.166 + static class CastInfo { 26.167 + CastKind kind; 26.168 + Type[] types; 26.169 + 26.170 + CastInfo(CastKind kind, Type... types) { 26.171 + this.kind = kind; 26.172 + this.types = types; 26.173 + } 26.174 + 26.175 + String getCast() { 26.176 + String temp = kind.castTemplate.replaceAll("#C", types[0].asString()); 26.177 + for (int i = 0; i < kind.interfaceBounds ; i++) { 26.178 + temp = temp.replace(String.format("#I%d", i), types[i + 1].asString()); 26.179 + } 26.180 + return temp; 26.181 + } 26.182 + 26.183 + boolean hasDuplicateTypes() { 26.184 + for (int i = 0 ; i < types.length ; i++) { 26.185 + for (int j = 0 ; j < types.length ; j++) { 26.186 + if (i != j && types[i] == types[j]) { 26.187 + return true; 26.188 + } 26.189 + } 26.190 + } 26.191 + return false; 26.192 + } 26.193 + 26.194 + boolean compatibleWith(ModifierKind mod, CastInfo that) { 26.195 + for (Type t1 : types) { 26.196 + for (Type t2 : that.types) { 26.197 + boolean compat = 26.198 + t1.subtypeOf(t2) || 26.199 + t2.subtypeOf(t1) || 26.200 + (t1.isInterface() && t2.isInterface()) || //side-cast (1) 26.201 + (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2) 26.202 + if (!compat) return false; 26.203 + } 26.204 + } 26.205 + return true; 26.206 + } 26.207 + } 26.208 + 26.209 + public static void main(String... args) throws Exception { 26.210 + //create default shared JavaCompiler - reused across multiple compilations 26.211 + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 26.212 + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); 26.213 + 26.214 + for (ModifierKind mod : ModifierKind.values()) { 26.215 + for (CastInfo cast1 : allCastInfo()) { 26.216 + for (CastInfo cast2 : allCastInfo()) { 26.217 + new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm); 26.218 + } 26.219 + } 26.220 + } 26.221 + System.out.println("Total check executed: " + checkCount); 26.222 + } 26.223 + 26.224 + static List<CastInfo> allCastInfo() { 26.225 + ListBuffer<CastInfo> buf = ListBuffer.lb(); 26.226 + for (CastKind kind : CastKind.values()) { 26.227 + for (ClassKind clazz : ClassKind.values()) { 26.228 + if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) { 26.229 + continue; 26.230 + } else if (kind.interfaceBounds == 0) { 26.231 + buf.append(new CastInfo(kind, clazz)); 26.232 + continue; 26.233 + } else { 26.234 + for (InterfaceKind intf1 : InterfaceKind.values()) { 26.235 + if (kind.interfaceBounds == 1) { 26.236 + buf.append(new CastInfo(kind, clazz, intf1)); 26.237 + continue; 26.238 + } else { 26.239 + for (InterfaceKind intf2 : InterfaceKind.values()) { 26.240 + if (kind.interfaceBounds == 2) { 26.241 + buf.append(new CastInfo(kind, clazz, intf1, intf2)); 26.242 + continue; 26.243 + } else { 26.244 + for (InterfaceKind intf3 : InterfaceKind.values()) { 26.245 + buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3)); 26.246 + continue; 26.247 + } 26.248 + } 26.249 + } 26.250 + } 26.251 + } 26.252 + } 26.253 + } 26.254 + } 26.255 + return buf.toList(); 26.256 + } 26.257 + 26.258 + ModifierKind mod; 26.259 + CastInfo cast1, cast2; 26.260 + JavaSource source; 26.261 + DiagnosticChecker diagChecker; 26.262 + 26.263 + IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) { 26.264 + this.mod = mod; 26.265 + this.cast1 = cast1; 26.266 + this.cast2 = cast2; 26.267 + this.source = new JavaSource(); 26.268 + this.diagChecker = new DiagnosticChecker(); 26.269 + } 26.270 + 26.271 + class JavaSource extends SimpleJavaFileObject { 26.272 + 26.273 + String bodyTemplate = "class Test {\n" + 26.274 + " void test() {\n" + 26.275 + " Object o = #C1#C2null;\n" + 26.276 + " } }"; 26.277 + 26.278 + String source = ""; 26.279 + 26.280 + public JavaSource() { 26.281 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 26.282 + for (ClassKind ck : ClassKind.values()) { 26.283 + source += ck.getDecl(mod); 26.284 + } 26.285 + for (InterfaceKind ik : InterfaceKind.values()) { 26.286 + source += ik.declStr; 26.287 + } 26.288 + source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast()); 26.289 + } 26.290 + 26.291 + @Override 26.292 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 26.293 + return source; 26.294 + } 26.295 + } 26.296 + 26.297 + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { 26.298 + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, 26.299 + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); 26.300 + try { 26.301 + ct.analyze(); 26.302 + } catch (Throwable ex) { 26.303 + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); 26.304 + } 26.305 + check(); 26.306 + } 26.307 + 26.308 + void check() { 26.309 + checkCount++; 26.310 + 26.311 + boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes(); 26.312 + 26.313 + errorExpected |= !cast2.compatibleWith(mod, cast1); 26.314 + 26.315 + if (errorExpected != diagChecker.errorFound) { 26.316 + throw new Error("invalid diagnostics for source:\n" + 26.317 + source.getCharContent(true) + 26.318 + "\nFound error: " + diagChecker.errorFound + 26.319 + "\nExpected error: " + errorExpected); 26.320 + } 26.321 + } 26.322 + 26.323 + static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 26.324 + 26.325 + boolean errorFound; 26.326 + 26.327 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 26.328 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 26.329 + errorFound = true; 26.330 + } 26.331 + } 26.332 + } 26.333 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java Fri Nov 30 15:14:48 2012 +0000 27.3 @@ -0,0 +1,191 @@ 27.4 +/* 27.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 27.7 + * 27.8 + * This code is free software; you can redistribute it and/or modify it 27.9 + * under the terms of the GNU General Public License version 2 only, as 27.10 + * published by the Free Software Foundation. 27.11 + * 27.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 27.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 27.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27.15 + * version 2 for more details (a copy is included in the LICENSE file that 27.16 + * accompanied this code). 27.17 + * 27.18 + * You should have received a copy of the GNU General Public License version 27.19 + * 2 along with this work; if not, write to the Free Software Foundation, 27.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 27.21 + * 27.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 27.23 + * or visit www.oracle.com if you need additional information or have any 27.24 + * questions. 27.25 + */ 27.26 + 27.27 +/* 27.28 + * @test 27.29 + * @bug 8002099 27.30 + * @summary Add support for intersection types in cast expression 27.31 + */ 27.32 + 27.33 +import com.sun.source.util.JavacTask; 27.34 +import java.net.URI; 27.35 +import java.util.Arrays; 27.36 +import javax.tools.Diagnostic; 27.37 +import javax.tools.JavaCompiler; 27.38 +import javax.tools.JavaFileObject; 27.39 +import javax.tools.SimpleJavaFileObject; 27.40 +import javax.tools.StandardJavaFileManager; 27.41 +import javax.tools.ToolProvider; 27.42 + 27.43 +public class IntersectionTypeParserTest { 27.44 + 27.45 + static int checkCount = 0; 27.46 + 27.47 + enum TypeKind { 27.48 + SIMPLE("A"), 27.49 + GENERIC("A<X>"), 27.50 + WILDCARD("A<? super X, ? extends Y>"); 27.51 + 27.52 + String typeStr; 27.53 + 27.54 + TypeKind(String typeStr) { 27.55 + this.typeStr = typeStr; 27.56 + } 27.57 + } 27.58 + 27.59 + enum ArrayKind { 27.60 + NONE(""), 27.61 + SINGLE("[]"), 27.62 + DOUBLE("[][]"); 27.63 + 27.64 + String arrStr; 27.65 + 27.66 + ArrayKind(String arrStr) { 27.67 + this.arrStr = arrStr; 27.68 + } 27.69 + } 27.70 + 27.71 + static class Type { 27.72 + TypeKind tk; 27.73 + ArrayKind ak; 27.74 + 27.75 + Type(TypeKind tk, ArrayKind ak) { 27.76 + this.tk = tk; 27.77 + this.ak = ak; 27.78 + } 27.79 + 27.80 + String asString() { 27.81 + return tk.typeStr + ak.arrStr; 27.82 + } 27.83 + } 27.84 + 27.85 + enum CastKind { 27.86 + ONE("(#T0)", 1), 27.87 + TWO("(#T0 & T1)", 2), 27.88 + THREE("(#T0 & #T1 & #T2)", 3); 27.89 + 27.90 + String castTemplate; 27.91 + int nBounds; 27.92 + 27.93 + CastKind(String castTemplate, int nBounds) { 27.94 + this.castTemplate = castTemplate; 27.95 + this.nBounds = nBounds; 27.96 + } 27.97 + 27.98 + String asString(Type... types) { 27.99 + String res = castTemplate; 27.100 + for (int i = 0; i < nBounds ; i++) { 27.101 + res = res.replaceAll(String.format("#T%d", i), types[i].asString()); 27.102 + } 27.103 + return res; 27.104 + } 27.105 + } 27.106 + 27.107 + public static void main(String... args) throws Exception { 27.108 + //create default shared JavaCompiler - reused across multiple compilations 27.109 + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 27.110 + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); 27.111 + 27.112 + for (CastKind ck : CastKind.values()) { 27.113 + for (TypeKind t1 : TypeKind.values()) { 27.114 + for (ArrayKind ak1 : ArrayKind.values()) { 27.115 + Type typ1 = new Type(t1, ak1); 27.116 + if (ck.nBounds == 1) { 27.117 + new IntersectionTypeParserTest(ck, typ1).run(comp, fm); 27.118 + continue; 27.119 + } 27.120 + for (TypeKind t2 : TypeKind.values()) { 27.121 + for (ArrayKind ak2 : ArrayKind.values()) { 27.122 + Type typ2 = new Type(t2, ak2); 27.123 + if (ck.nBounds == 2) { 27.124 + new IntersectionTypeParserTest(ck, typ1, typ2).run(comp, fm); 27.125 + continue; 27.126 + } 27.127 + for (TypeKind t3 : TypeKind.values()) { 27.128 + for (ArrayKind ak3 : ArrayKind.values()) { 27.129 + Type typ3 = new Type(t3, ak3); 27.130 + new IntersectionTypeParserTest(ck, typ1, typ2, typ3).run(comp, fm); 27.131 + } 27.132 + } 27.133 + } 27.134 + } 27.135 + } 27.136 + } 27.137 + } 27.138 + System.out.println("Total check executed: " + checkCount); 27.139 + } 27.140 + 27.141 + CastKind ck; 27.142 + Type[] types; 27.143 + JavaSource source; 27.144 + DiagnosticChecker diagChecker; 27.145 + 27.146 + IntersectionTypeParserTest(CastKind ck, Type... types) { 27.147 + this.ck = ck; 27.148 + this.types = types; 27.149 + this.source = new JavaSource(); 27.150 + this.diagChecker = new DiagnosticChecker(); 27.151 + } 27.152 + 27.153 + class JavaSource extends SimpleJavaFileObject { 27.154 + 27.155 + String bodyTemplate = "class Test {\n" + 27.156 + " void test() {\n" + 27.157 + " Object o = #Cnull;\n" + 27.158 + " } }"; 27.159 + 27.160 + String source = ""; 27.161 + 27.162 + public JavaSource() { 27.163 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 27.164 + source += bodyTemplate.replaceAll("#C", ck.asString(types)); 27.165 + } 27.166 + 27.167 + @Override 27.168 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 27.169 + return source; 27.170 + } 27.171 + } 27.172 + 27.173 + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { 27.174 + checkCount++; 27.175 + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, 27.176 + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); 27.177 + ct.parse(); 27.178 + if (diagChecker.errorFound) { 27.179 + throw new Error("Unexpected parser error for source:\n" + 27.180 + source.getCharContent(true)); 27.181 + } 27.182 + } 27.183 + 27.184 + static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 27.185 + 27.186 + boolean errorFound; 27.187 + 27.188 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 27.189 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 27.190 + errorFound = true; 27.191 + } 27.192 + } 27.193 + } 27.194 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/test/tools/javac/cast/intersection/model/Check.java Fri Nov 30 15:14:48 2012 +0000 28.3 @@ -0,0 +1,27 @@ 28.4 +/* 28.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 28.7 + * 28.8 + * This code is free software; you can redistribute it and/or modify it 28.9 + * under the terms of the GNU General Public License version 2 only, as 28.10 + * published by the Free Software Foundation. 28.11 + * 28.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 28.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 28.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28.15 + * version 2 for more details (a copy is included in the LICENSE file that 28.16 + * accompanied this code). 28.17 + * 28.18 + * You should have received a copy of the GNU General Public License version 28.19 + * 2 along with this work; if not, write to the Free Software Foundation, 28.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 28.21 + * 28.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28.23 + * or visit www.oracle.com if you need additional information or have any 28.24 + * questions. 28.25 + */ 28.26 + 28.27 +/** 28.28 + * Annotation used by ModelChecker to mark the class whose model is to be checked 28.29 + */ 28.30 +@interface Check {}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java Fri Nov 30 15:14:48 2012 +0000 29.3 @@ -0,0 +1,29 @@ 29.4 +/* 29.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 29.7 + * 29.8 + * This code is free software; you can redistribute it and/or modify it 29.9 + * under the terms of the GNU General Public License version 2 only, as 29.10 + * published by the Free Software Foundation. 29.11 + * 29.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 29.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 29.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 29.15 + * version 2 for more details (a copy is included in the LICENSE file that 29.16 + * accompanied this code). 29.17 + * 29.18 + * You should have received a copy of the GNU General Public License version 29.19 + * 2 along with this work; if not, write to the Free Software Foundation, 29.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 29.21 + * 29.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 29.23 + * or visit www.oracle.com if you need additional information or have any 29.24 + * questions. 29.25 + */ 29.26 + 29.27 +/** 29.28 + * Used by ModelChecker to validate the modeling information of a union type. 29.29 + */ 29.30 +@interface IntersectionTypeInfo { 29.31 + String[] value(); 29.32 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/test/tools/javac/cast/intersection/model/Member.java Fri Nov 30 15:14:48 2012 +0000 30.3 @@ -0,0 +1,31 @@ 30.4 +/* 30.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 30.7 + * 30.8 + * This code is free software; you can redistribute it and/or modify it 30.9 + * under the terms of the GNU General Public License version 2 only, as 30.10 + * published by the Free Software Foundation. 30.11 + * 30.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 30.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 30.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30.15 + * version 2 for more details (a copy is included in the LICENSE file that 30.16 + * accompanied this code). 30.17 + * 30.18 + * You should have received a copy of the GNU General Public License version 30.19 + * 2 along with this work; if not, write to the Free Software Foundation, 30.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 30.21 + * 30.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 30.23 + * or visit www.oracle.com if you need additional information or have any 30.24 + * questions. 30.25 + */ 30.26 + 30.27 +import javax.lang.model.element.ElementKind; 30.28 + 30.29 +/** 30.30 + * Annotation used by ModelChecker to mark a member that is to be checked 30.31 + */ 30.32 +@interface Member { 30.33 + ElementKind value(); 30.34 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/test/tools/javac/cast/intersection/model/Model01.java Fri Nov 30 15:14:48 2012 +0000 31.3 @@ -0,0 +1,52 @@ 31.4 +/* 31.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 31.7 + * 31.8 + * This code is free software; you can redistribute it and/or modify it 31.9 + * under the terms of the GNU General Public License version 2 only, as 31.10 + * published by the Free Software Foundation. 31.11 + * 31.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 31.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 31.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31.15 + * version 2 for more details (a copy is included in the LICENSE file that 31.16 + * accompanied this code). 31.17 + * 31.18 + * You should have received a copy of the GNU General Public License version 31.19 + * 2 along with this work; if not, write to the Free Software Foundation, 31.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 31.21 + * 31.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 31.23 + * or visit www.oracle.com if you need additional information or have any 31.24 + * questions. 31.25 + */ 31.26 + 31.27 +/* 31.28 + * @test 31.29 + * @bug 8002099 31.30 + * @summary Add support for intersection types in cast expression 31.31 + * @library ../../../lib 31.32 + * @build JavacTestingAbstractProcessor ModelChecker 31.33 + * @compile -XDallowIntersectionTypes -processor ModelChecker Model01.java 31.34 + */ 31.35 + 31.36 +import javax.lang.model.element.ElementKind; 31.37 + 31.38 +@Check 31.39 +class Test { 31.40 + 31.41 + interface A { 31.42 + @Member(ElementKind.METHOD) 31.43 + public void m1(); 31.44 + } 31.45 + 31.46 + interface B { 31.47 + @Member(ElementKind.METHOD) 31.48 + public void m2(); 31.49 + } 31.50 + 31.51 + void test(){ 31.52 + @IntersectionTypeInfo({"java.lang.Object", "Test.A", "Test.B"}) 31.53 + Object o = (A & B)null; 31.54 + } 31.55 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/test/tools/javac/cast/intersection/model/ModelChecker.java Fri Nov 30 15:14:48 2012 +0000 32.3 @@ -0,0 +1,153 @@ 32.4 +/* 32.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 32.7 + * 32.8 + * This code is free software; you can redistribute it and/or modify it 32.9 + * under the terms of the GNU General Public License version 2 only, as 32.10 + * published by the Free Software Foundation. 32.11 + * 32.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 32.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 32.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32.15 + * version 2 for more details (a copy is included in the LICENSE file that 32.16 + * accompanied this code). 32.17 + * 32.18 + * You should have received a copy of the GNU General Public License version 32.19 + * 2 along with this work; if not, write to the Free Software Foundation, 32.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 32.21 + * 32.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 32.23 + * or visit www.oracle.com if you need additional information or have any 32.24 + * questions. 32.25 + */ 32.26 + 32.27 +import com.sun.source.tree.ExpressionTree; 32.28 +import com.sun.source.tree.Tree; 32.29 +import com.sun.source.tree.TypeCastTree; 32.30 +import com.sun.source.tree.VariableTree; 32.31 +import com.sun.source.util.TreePathScanner; 32.32 +import com.sun.source.util.Trees; 32.33 +import com.sun.source.util.TreePath; 32.34 +import com.sun.tools.javac.tree.JCTree.JCExpression; 32.35 + 32.36 +import java.util.Set; 32.37 + 32.38 +import javax.annotation.processing.RoundEnvironment; 32.39 +import javax.annotation.processing.SupportedAnnotationTypes; 32.40 +import javax.lang.model.element.Element; 32.41 +import javax.lang.model.element.TypeElement; 32.42 +import javax.lang.model.type.TypeMirror; 32.43 +import javax.lang.model.type.TypeKind; 32.44 +import javax.lang.model.type.IntersectionType; 32.45 +import javax.lang.model.type.UnknownTypeException; 32.46 +import javax.lang.model.util.SimpleTypeVisitor6; 32.47 +import javax.lang.model.util.SimpleTypeVisitor7; 32.48 + 32.49 +@SupportedAnnotationTypes("Check") 32.50 +public class ModelChecker extends JavacTestingAbstractProcessor { 32.51 + 32.52 + @Override 32.53 + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 32.54 + if (roundEnv.processingOver()) 32.55 + return true; 32.56 + 32.57 + Trees trees = Trees.instance(processingEnv); 32.58 + 32.59 + TypeElement testAnno = elements.getTypeElement("Check"); 32.60 + for (Element elem: roundEnv.getElementsAnnotatedWith(testAnno)) { 32.61 + TreePath p = trees.getPath(elem); 32.62 + new IntersectionCastTester(trees).scan(p, null); 32.63 + } 32.64 + return true; 32.65 + } 32.66 + 32.67 + class IntersectionCastTester extends TreePathScanner<Void, Void> { 32.68 + Trees trees; 32.69 + 32.70 + public IntersectionCastTester(Trees trees) { 32.71 + super(); 32.72 + this.trees = trees; 32.73 + } 32.74 + 32.75 + @Override 32.76 + public Void visitVariable(VariableTree node, Void p) { 32.77 + 32.78 + TreePath varPath = new TreePath(getCurrentPath(), node); 32.79 + Element v = trees.getElement(varPath); 32.80 + 32.81 + IntersectionTypeInfo it = v.getAnnotation(IntersectionTypeInfo.class); 32.82 + assertTrue(it != null, "IntersectionType annotation must be present"); 32.83 + 32.84 + ExpressionTree varInit = node.getInitializer(); 32.85 + assertTrue(varInit != null && varInit.getKind() == Tree.Kind.TYPE_CAST, 32.86 + "variable must have be initialized to an expression containing an intersection type cast"); 32.87 + 32.88 + TypeMirror t = ((JCExpression)((TypeCastTree)varInit).getType()).type; 32.89 + 32.90 + validateIntersectionTypeInfo(t, it); 32.91 + 32.92 + for (Element e2 : types.asElement(t).getEnclosedElements()) { 32.93 + assertTrue(false, "an intersection type has no declared members"); 32.94 + } 32.95 + 32.96 + for (Element e2 : elements.getAllMembers((TypeElement)types.asElement(t))) { 32.97 + Member m = e2.getAnnotation(Member.class); 32.98 + if (m != null) { 32.99 + assertTrue(e2.getKind() == m.value(), "Expected " + m.value() + " - found " + e2.getKind()); 32.100 + } 32.101 + } 32.102 + 32.103 + assertTrue(assertionCount == 10, "Expected 10 assertions - found " + assertionCount); 32.104 + return super.visitVariable(node, p); 32.105 + } 32.106 + } 32.107 + 32.108 + private void validateIntersectionTypeInfo(TypeMirror expectedIntersectionType, IntersectionTypeInfo it) { 32.109 + 32.110 + assertTrue(expectedIntersectionType.getKind() == TypeKind.INTERSECTION, "INTERSECTION kind expected"); 32.111 + 32.112 + try { 32.113 + new SimpleTypeVisitor6<Void, Void>(){}.visit(expectedIntersectionType); 32.114 + throw new RuntimeException("Expected UnknownTypeException not thrown."); 32.115 + } catch (UnknownTypeException ute) { 32.116 + ; // Expected 32.117 + } 32.118 + 32.119 + try { 32.120 + new SimpleTypeVisitor7<Void, Void>(){}.visit(expectedIntersectionType); 32.121 + throw new RuntimeException("Expected UnknownTypeException not thrown."); 32.122 + } catch (UnknownTypeException ute) { 32.123 + ; // Expected 32.124 + } 32.125 + 32.126 + IntersectionType intersectionType = new SimpleTypeVisitor<IntersectionType, Void>(){ 32.127 + @Override 32.128 + protected IntersectionType defaultAction(TypeMirror e, Void p) {return null;} 32.129 + 32.130 + @Override 32.131 + public IntersectionType visitIntersection(IntersectionType t, Void p) {return t;} 32.132 + }.visit(expectedIntersectionType); 32.133 + assertTrue(intersectionType != null, "Must get a non-null intersection type."); 32.134 + 32.135 + assertTrue(it.value().length == intersectionType.getBounds().size(), "Cardinalities do not match"); 32.136 + 32.137 + String[] typeNames = it.value(); 32.138 + for(int i = 0; i < typeNames.length; i++) { 32.139 + TypeMirror typeFromAnnotation = nameToType(typeNames[i]); 32.140 + assertTrue(types.isSameType(typeFromAnnotation, intersectionType.getBounds().get(i)), 32.141 + "Types were not equal."); 32.142 + } 32.143 + } 32.144 + 32.145 + private TypeMirror nameToType(String name) { 32.146 + return elements.getTypeElement(name).asType(); 32.147 + } 32.148 + 32.149 + private static void assertTrue(boolean cond, String msg) { 32.150 + assertionCount++; 32.151 + if (!cond) 32.152 + throw new AssertionError(msg); 32.153 + } 32.154 + 32.155 + static int assertionCount = 0; 32.156 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java Fri Nov 30 15:14:48 2012 +0000 33.3 @@ -0,0 +1,29 @@ 33.4 +/* 33.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 33.7 + * 33.8 + * This code is free software; you can redistribute it and/or modify it 33.9 + * under the terms of the GNU General Public License version 2 only, as 33.10 + * published by the Free Software Foundation. 33.11 + * 33.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 33.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 33.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 33.15 + * version 2 for more details (a copy is included in the LICENSE file that 33.16 + * accompanied this code). 33.17 + * 33.18 + * You should have received a copy of the GNU General Public License version 33.19 + * 2 along with this work; if not, write to the Free Software Foundation, 33.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 33.21 + * 33.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 33.23 + * or visit www.oracle.com if you need additional information or have any 33.24 + * questions. 33.25 + */ 33.26 + 33.27 +// key: compiler.err.intersection.types.in.cast.not.supported.in.source 33.28 +// options: -source 7 -Xlint:-options 33.29 + 33.30 +interface IntersectionTypesInCastNotSupported { 33.31 + Object o = (A & B)null; 33.32 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java Fri Nov 30 15:14:48 2012 +0000 34.3 @@ -0,0 +1,30 @@ 34.4 +/* 34.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 34.7 + * 34.8 + * This code is free software; you can redistribute it and/or modify it 34.9 + * under the terms of the GNU General Public License version 2 only, as 34.10 + * published by the Free Software Foundation. 34.11 + * 34.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 34.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 34.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 34.15 + * version 2 for more details (a copy is included in the LICENSE file that 34.16 + * accompanied this code). 34.17 + * 34.18 + * You should have received a copy of the GNU General Public License version 34.19 + * 2 along with this work; if not, write to the Free Software Foundation, 34.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 34.21 + * 34.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 34.23 + * or visit www.oracle.com if you need additional information or have any 34.24 + * questions. 34.25 + */ 34.26 + 34.27 +// key: compiler.err.prob.found.req 34.28 +// key: compiler.misc.secondary.bound.must.be.marker.intf 34.29 +// options: -XDallowIntersectionTypes 34.30 + 34.31 +class SecondaryBoundMustBeMarkerInterface { 34.32 + Runnable r = (Runnable & Comparable<?>)()->{}; 34.33 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/test/tools/javac/lambda/Intersection01.java Fri Nov 30 15:14:48 2012 +0000 35.3 @@ -0,0 +1,42 @@ 35.4 +/* 35.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 35.7 + * 35.8 + * This code is free software; you can redistribute it and/or modify it 35.9 + * under the terms of the GNU General Public License version 2 only, as 35.10 + * published by the Free Software Foundation. 35.11 + * 35.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 35.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 35.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 35.15 + * version 2 for more details (a copy is included in the LICENSE file that 35.16 + * accompanied this code). 35.17 + * 35.18 + * You should have received a copy of the GNU General Public License version 35.19 + * 2 along with this work; if not, write to the Free Software Foundation, 35.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 35.21 + * 35.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 35.23 + * or visit www.oracle.com if you need additional information or have any 35.24 + * questions. 35.25 + */ 35.26 + 35.27 +/* 35.28 + * @test 35.29 + * @bug 8002099 35.30 + * @summary Add support for intersection types in cast expression 35.31 + * @compile/fail/ref=Intersection01.out -XDallowIntersectionTypes -XDrawDiagnostics Intersection01.java 35.32 + */ 35.33 +class Intersection01 { 35.34 + 35.35 + interface SAM { 35.36 + void m(); 35.37 + } 35.38 + 35.39 + Object o1 = (java.io.Serializable & SAM)()->{}; 35.40 + Object o2 = (SAM & java.io.Serializable)()->{}; 35.41 + Object o3 = (java.io.Serializable & SAM)Intersection01::m; 35.42 + Object o4 = (SAM & java.io.Serializable)Intersection01::m; 35.43 + 35.44 + static void m() { } 35.45 +}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/test/tools/javac/lambda/Intersection01.out Fri Nov 30 15:14:48 2012 +0000 36.3 @@ -0,0 +1,3 @@ 36.4 +Intersection01.java:36:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable)) 36.5 +Intersection01.java:38:45: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf.1: (compiler.misc.no.abstracts: kindname.interface, java.io.Serializable)) 36.6 +2 errors
37.1 --- a/test/tools/javac/lambda/LambdaParserTest.java Fri Nov 30 15:14:36 2012 +0000 37.2 +++ b/test/tools/javac/lambda/LambdaParserTest.java Fri Nov 30 15:14:48 2012 +0000 37.3 @@ -90,9 +90,14 @@ 37.4 enum LambdaParameterKind { 37.5 IMPLICIT(""), 37.6 EXPLIICT_SIMPLE("A"), 37.7 + EXPLIICT_SIMPLE_ARR1("A[]"), 37.8 + EXPLIICT_SIMPLE_ARR2("A[][]"), 37.9 EXPLICIT_VARARGS("A..."), 37.10 EXPLICIT_GENERIC1("A<X>"), 37.11 - EXPLICIT_GENERIC3("A<? extends X, ? super Y>"); 37.12 + EXPLICIT_GENERIC2("A<? extends X, ? super Y>"), 37.13 + EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>..."), 37.14 + EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]"), 37.15 + EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]"); 37.16 37.17 String parameterType; 37.18 37.19 @@ -103,6 +108,11 @@ 37.20 boolean explicit() { 37.21 return this != IMPLICIT; 37.22 } 37.23 + 37.24 + boolean isVarargs() { 37.25 + return this == EXPLICIT_VARARGS || 37.26 + this == EXPLICIT_GENERIC2_VARARGS; 37.27 + } 37.28 } 37.29 37.30 enum ModifierKind { 37.31 @@ -253,7 +263,7 @@ 37.32 37.33 if (lk.arity() == 2 && 37.34 (pk1.explicit() != pk2.explicit() || 37.35 - pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) { 37.36 + pk1.isVarargs())) { 37.37 errorExpected = true; 37.38 } 37.39
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java Fri Nov 30 15:14:48 2012 +0000 38.3 @@ -0,0 +1,294 @@ 38.4 +/* 38.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 38.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 38.7 + * 38.8 + * This code is free software; you can redistribute it and/or modify it 38.9 + * under the terms of the GNU General Public License version 2 only, as 38.10 + * published by the Free Software Foundation. 38.11 + * 38.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 38.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 38.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 38.15 + * version 2 for more details (a copy is included in the LICENSE file that 38.16 + * accompanied this code). 38.17 + * 38.18 + * You should have received a copy of the GNU General Public License version 38.19 + * 2 along with this work; if not, write to the Free Software Foundation, 38.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 38.21 + * 38.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 38.23 + * or visit www.oracle.com if you need additional information or have any 38.24 + * questions. 38.25 + */ 38.26 + 38.27 +/* 38.28 + * @test 38.29 + * @bug 8002099 38.30 + * @summary Add support for intersection types in cast expression 38.31 + */ 38.32 + 38.33 +import com.sun.source.util.JavacTask; 38.34 +import com.sun.tools.javac.util.List; 38.35 +import com.sun.tools.javac.util.ListBuffer; 38.36 +import java.net.URI; 38.37 +import java.util.Arrays; 38.38 +import javax.tools.Diagnostic; 38.39 +import javax.tools.JavaCompiler; 38.40 +import javax.tools.JavaFileObject; 38.41 +import javax.tools.SimpleJavaFileObject; 38.42 +import javax.tools.StandardJavaFileManager; 38.43 +import javax.tools.ToolProvider; 38.44 + 38.45 +public class IntersectionTargetTypeTest { 38.46 + 38.47 + static int checkCount = 0; 38.48 + 38.49 + enum BoundKind { 38.50 + INTF, 38.51 + CLASS, 38.52 + SAM, 38.53 + ZAM; 38.54 + } 38.55 + 38.56 + enum MethodKind { 38.57 + NONE, 38.58 + ABSTRACT, 38.59 + DEFAULT; 38.60 + } 38.61 + 38.62 + enum TypeKind { 38.63 + A("interface A { }\n", "A", BoundKind.ZAM), 38.64 + B("interface B { default void m() { } }\n", "B", BoundKind.ZAM), 38.65 + C("interface C { void m(); }\n", "C", BoundKind.SAM), 38.66 + D("interface D extends B { }\n", "D", BoundKind.ZAM), 38.67 + E("interface E extends C { }\n", "E", BoundKind.SAM), 38.68 + F("interface F extends C { void g(); }\n", "F", BoundKind.INTF), 38.69 + G("interface G extends B { void g(); }\n", "G", BoundKind.SAM), 38.70 + H("interface H extends A { void g(); }\n", "H", BoundKind.SAM), 38.71 + OBJECT("", "Object", BoundKind.CLASS), 38.72 + STRING("", "String", BoundKind.CLASS); 38.73 + 38.74 + String declStr; 38.75 + String typeStr; 38.76 + BoundKind boundKind; 38.77 + 38.78 + private TypeKind(String declStr, String typeStr, BoundKind boundKind) { 38.79 + this.declStr = declStr; 38.80 + this.typeStr = typeStr; 38.81 + this.boundKind = boundKind; 38.82 + } 38.83 + 38.84 + boolean compatibleSupertype(TypeKind tk) { 38.85 + if (tk == this) return true; 38.86 + switch (tk) { 38.87 + case B: 38.88 + return this != C && this != E && this != F; 38.89 + case C: 38.90 + return this != B && this != C && this != D && this != G; 38.91 + case D: return compatibleSupertype(B); 38.92 + case E: 38.93 + case F: return compatibleSupertype(C); 38.94 + case G: return compatibleSupertype(B); 38.95 + case H: return compatibleSupertype(A); 38.96 + default: 38.97 + return true; 38.98 + } 38.99 + } 38.100 + } 38.101 + 38.102 + enum CastKind { 38.103 + ONE_ARY("(#B0)", 1), 38.104 + TWO_ARY("(#B0 & #B1)", 2), 38.105 + THREE_ARY("(#B0 & #B1 & #B2)", 3); 38.106 + 38.107 + String castTemplate; 38.108 + int nbounds; 38.109 + 38.110 + CastKind(String castTemplate, int nbounds) { 38.111 + this.castTemplate = castTemplate; 38.112 + this.nbounds = nbounds; 38.113 + } 38.114 + } 38.115 + 38.116 + enum ExpressionKind { 38.117 + LAMBDA("()->{}", true), 38.118 + MREF("this::m", true), 38.119 + //COND_LAMBDA("(true ? ()->{} : ()->{})", true), re-enable if spec allows this 38.120 + //COND_MREF("(true ? this::m : this::m)", true), 38.121 + STANDALONE("null", false); 38.122 + 38.123 + String exprString; 38.124 + boolean isFunctional; 38.125 + 38.126 + private ExpressionKind(String exprString, boolean isFunctional) { 38.127 + this.exprString = exprString; 38.128 + this.isFunctional = isFunctional; 38.129 + } 38.130 + } 38.131 + 38.132 + static class CastInfo { 38.133 + CastKind kind; 38.134 + TypeKind[] types; 38.135 + 38.136 + CastInfo(CastKind kind, TypeKind... types) { 38.137 + this.kind = kind; 38.138 + this.types = types; 38.139 + } 38.140 + 38.141 + String getCast() { 38.142 + String temp = kind.castTemplate; 38.143 + for (int i = 0; i < kind.nbounds ; i++) { 38.144 + temp = temp.replace(String.format("#B%d", i), types[i].typeStr); 38.145 + } 38.146 + return temp; 38.147 + } 38.148 + 38.149 + boolean wellFormed() { 38.150 + //check for duplicate types 38.151 + for (int i = 0 ; i < types.length ; i++) { 38.152 + for (int j = 0 ; j < types.length ; j++) { 38.153 + if (i != j && types[i] == types[j]) { 38.154 + return false; 38.155 + } 38.156 + } 38.157 + } 38.158 + //check that classes only appear as first bound 38.159 + boolean classOk = true; 38.160 + for (int i = 0 ; i < types.length ; i++) { 38.161 + if (types[i].boundKind == BoundKind.CLASS && 38.162 + !classOk) { 38.163 + return false; 38.164 + } 38.165 + classOk = false; 38.166 + } 38.167 + //check that supertypes are mutually compatible 38.168 + for (int i = 0 ; i < types.length ; i++) { 38.169 + for (int j = 0 ; j < types.length ; j++) { 38.170 + if (!types[i].compatibleSupertype(types[j]) && i != j) { 38.171 + return false; 38.172 + } 38.173 + } 38.174 + } 38.175 + return true; 38.176 + } 38.177 + } 38.178 + 38.179 + public static void main(String... args) throws Exception { 38.180 + //create default shared JavaCompiler - reused across multiple compilations 38.181 + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 38.182 + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); 38.183 + 38.184 + for (CastInfo cInfo : allCastInfo()) { 38.185 + for (ExpressionKind ek : ExpressionKind.values()) { 38.186 + new IntersectionTargetTypeTest(cInfo, ek).run(comp, fm); 38.187 + } 38.188 + } 38.189 + System.out.println("Total check executed: " + checkCount); 38.190 + } 38.191 + 38.192 + static List<CastInfo> allCastInfo() { 38.193 + ListBuffer<CastInfo> buf = ListBuffer.lb(); 38.194 + for (CastKind kind : CastKind.values()) { 38.195 + for (TypeKind b1 : TypeKind.values()) { 38.196 + if (kind.nbounds == 1) { 38.197 + buf.append(new CastInfo(kind, b1)); 38.198 + continue; 38.199 + } else { 38.200 + for (TypeKind b2 : TypeKind.values()) { 38.201 + if (kind.nbounds == 2) { 38.202 + buf.append(new CastInfo(kind, b1, b2)); 38.203 + continue; 38.204 + } else { 38.205 + for (TypeKind b3 : TypeKind.values()) { 38.206 + buf.append(new CastInfo(kind, b1, b2, b3)); 38.207 + } 38.208 + } 38.209 + } 38.210 + } 38.211 + } 38.212 + } 38.213 + return buf.toList(); 38.214 + } 38.215 + 38.216 + CastInfo cInfo; 38.217 + ExpressionKind ek; 38.218 + JavaSource source; 38.219 + DiagnosticChecker diagChecker; 38.220 + 38.221 + IntersectionTargetTypeTest(CastInfo cInfo, ExpressionKind ek) { 38.222 + this.cInfo = cInfo; 38.223 + this.ek = ek; 38.224 + this.source = new JavaSource(); 38.225 + this.diagChecker = new DiagnosticChecker(); 38.226 + } 38.227 + 38.228 + class JavaSource extends SimpleJavaFileObject { 38.229 + 38.230 + String bodyTemplate = "class Test {\n" + 38.231 + " void m() { }\n" + 38.232 + " void test() {\n" + 38.233 + " Object o = #C#E;\n" + 38.234 + " } }"; 38.235 + 38.236 + String source = ""; 38.237 + 38.238 + public JavaSource() { 38.239 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 38.240 + for (TypeKind tk : TypeKind.values()) { 38.241 + source += tk.declStr; 38.242 + } 38.243 + source += bodyTemplate.replaceAll("#C", cInfo.getCast()).replaceAll("#E", ek.exprString); 38.244 + } 38.245 + 38.246 + @Override 38.247 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 38.248 + return source; 38.249 + } 38.250 + } 38.251 + 38.252 + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { 38.253 + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, 38.254 + Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source)); 38.255 + try { 38.256 + ct.analyze(); 38.257 + } catch (Throwable ex) { 38.258 + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); 38.259 + } 38.260 + check(); 38.261 + } 38.262 + 38.263 + void check() { 38.264 + checkCount++; 38.265 + 38.266 + boolean errorExpected = !cInfo.wellFormed(); 38.267 + 38.268 + if (ek.isFunctional) { 38.269 + //first bound must be a SAM 38.270 + errorExpected |= cInfo.types[0].boundKind != BoundKind.SAM; 38.271 + if (cInfo.types.length > 1) { 38.272 + //additional bounds must be ZAMs 38.273 + for (int i = 1; i < cInfo.types.length; i++) { 38.274 + errorExpected |= cInfo.types[i].boundKind != BoundKind.ZAM; 38.275 + } 38.276 + } 38.277 + } 38.278 + 38.279 + if (errorExpected != diagChecker.errorFound) { 38.280 + throw new Error("invalid diagnostics for source:\n" + 38.281 + source.getCharContent(true) + 38.282 + "\nFound error: " + diagChecker.errorFound + 38.283 + "\nExpected error: " + errorExpected); 38.284 + } 38.285 + } 38.286 + 38.287 + static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 38.288 + 38.289 + boolean errorFound; 38.290 + 38.291 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 38.292 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 38.293 + errorFound = true; 38.294 + } 38.295 + } 38.296 + } 38.297 +}