8002099: Add support for intersection types in cast expression

Fri, 30 Nov 2012 15:14:48 +0000

author
mcimadamore
date
Fri, 30 Nov 2012 15:14:48 +0000
changeset 1436
f6f1fd261f57
parent 1435
9b26c96f5138
child 1437
98e14fc9ee11

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

src/share/classes/com/sun/source/tree/IntersectionTypeTree.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/source/tree/Tree.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/source/tree/TreeVisitor.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/source/util/SimpleTreeVisitor.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/source/util/TreeScanner.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/code/Source.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/code/Type.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/code/Types.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/TransTypes.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/ClassReader.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/model/JavacTypes.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/JavacParser.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/JCTree.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/Pretty.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeCopier.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeMaker.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeScanner.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java file | annotate | diff | comparison | revisions
src/share/classes/javax/lang/model/type/IntersectionType.java file | annotate | diff | comparison | revisions
src/share/classes/javax/lang/model/type/TypeKind.java file | annotate | diff | comparison | revisions
src/share/classes/javax/lang/model/type/TypeVisitor.java file | annotate | diff | comparison | revisions
src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java file | annotate | diff | comparison | revisions
src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/IntersectionTypeCastTest.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/IntersectionTypeParserTest.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/model/Check.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/model/Member.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/model/Model01.java file | annotate | diff | comparison | revisions
test/tools/javac/cast/intersection/model/ModelChecker.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/Intersection01.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/Intersection01.out file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaParserTest.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java file | annotate | diff | comparison | revisions
     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 '&lt;' it could be an unbound
  13.207 +     * method reference or a binary expression. To disambiguate, look for a
  13.208 +     * matching '&gt;' 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 +}

mercurial