--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for an intersection type in a cast expression.
+ *
+ * @author Maurizio Cimadamore
+ *
+ * @since 1.8
+ */
+public interface IntersectionTypeTree extends Tree {
+ List<? extends Tree> getBounds();
+}
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java Mon Dec 10 20:59:38 2012 -0800
@@ -247,6 +247,11 @@
UNION_TYPE(UnionTypeTree.class),
/**
+ * Used for instances of {@link IntersectionTypeTree}.
+ */
+ INTERSECTION_TYPE(IntersectionTypeTree.class),
+
+ /**
* Used for instances of {@link TypeCastTree}.
*/
TYPE_CAST(TypeCastTree.class),
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Mon Dec 10 20:59:38 2012 -0800
@@ -98,6 +98,7 @@
R visitTry(TryTree node, P p);
R visitParameterizedType(ParameterizedTypeTree node, P p);
R visitUnionType(UnionTypeTree node, P p);
+ R visitIntersectionType(IntersectionTypeTree node, P p);
R visitArrayType(ArrayTypeTree node, P p);
R visitTypeCast(TypeCastTree node, P p);
R visitPrimitiveType(PrimitiveTypeTree node, P p);
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Mon Dec 10 20:59:38 2012 -0800
@@ -240,6 +240,10 @@
return defaultAction(node, p);
}
+ public R visitIntersectionType(IntersectionTypeTree node, P p) {
+ return defaultAction(node, p);
+ }
+
public R visitTypeParameter(TypeParameterTree node, P p) {
return defaultAction(node, p);
}
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Mon Dec 10 20:59:38 2012 -0800
@@ -371,6 +371,10 @@
return scan(node.getTypeAlternatives(), p);
}
+ public R visitIntersectionType(IntersectionTypeTree node, P p) {
+ return scan(node.getBounds(), p);
+ }
+
public R visitTypeParameter(TypeParameterTree node, P p) {
R r = scan(node.getBounds(), p);
return r;
--- a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java Mon Dec 10 20:59:38 2012 -0800
@@ -71,11 +71,16 @@
SHORT(3),
/** Wide opcode is not followed by any operands. */
WIDE_NO_OPERANDS(2),
+ /** Wide opcode is followed by a 2-byte index into the local variables array. */
+ WIDE_LOCAL(4),
/** Wide opcode is followed by a 2-byte index into the constant pool. */
WIDE_CPREF_W(4),
/** Wide opcode is followed by a 2-byte index into the constant pool,
* and a signed short value. */
WIDE_CPREF_W_SHORT(6),
+ /** Wide opcode is followed by a 2-byte reference to a local variable,
+ * and a signed short value. */
+ WIDE_LOCAL_SHORT(6),
/** Opcode was not recognized. */
UNKNOWN(1);
@@ -101,7 +106,7 @@
R visitConstantPoolRef(Instruction instr, int index, P p);
/** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */
R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p);
- /** See {@link Kind#LOCAL}. */
+ /** See {@link Kind#LOCAL}, {@link Kind#WIDE_LOCAL}. */
R visitLocal(Instruction instr, int index, P p);
/** See {@link Kind#LOCAL_BYTE}. */
R visitLocalAndValue(Instruction instr, int index, int value, P p);
@@ -315,6 +320,9 @@
case WIDE_NO_OPERANDS:
return visitor.visitNoOperands(this, p);
+ case WIDE_LOCAL:
+ return visitor.visitLocal(this, getUnsignedShort(2), p);
+
case WIDE_CPREF_W:
return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p);
@@ -322,6 +330,10 @@
return visitor.visitConstantPoolRefAndValue(
this, getUnsignedShort(2), getUnsignedByte(4), p);
+ case WIDE_LOCAL_SHORT:
+ return visitor.visitLocalAndValue(
+ this, getUnsignedShort(2), getShort(4), p);
+
case UNKNOWN:
return visitor.visitUnknown(this, p);
--- a/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Opcode.java Mon Dec 10 20:59:38 2012 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -246,18 +246,18 @@
// impdep 0xff: Picojava priv
// wide opcodes
- ILOAD_W(0xc415, WIDE_CPREF_W),
- LLOAD_W(0xc416, WIDE_CPREF_W),
- FLOAD_W(0xc417, WIDE_CPREF_W),
- DLOAD_W(0xc418, WIDE_CPREF_W),
- ALOAD_W(0xc419, WIDE_CPREF_W),
- ISTORE_W(0xc436, WIDE_CPREF_W),
- LSTORE_W(0xc437, WIDE_CPREF_W),
- FSTORE_W(0xc438, WIDE_CPREF_W),
- DSTORE_W(0xc439, WIDE_CPREF_W),
- ASTORE_W(0xc43a, WIDE_CPREF_W),
- IINC_W(0xc484, WIDE_CPREF_W_SHORT),
- RET_W(0xc4a9, WIDE_CPREF_W),
+ ILOAD_W(0xc415, WIDE_LOCAL),
+ LLOAD_W(0xc416, WIDE_LOCAL),
+ FLOAD_W(0xc417, WIDE_LOCAL),
+ DLOAD_W(0xc418, WIDE_LOCAL),
+ ALOAD_W(0xc419, WIDE_LOCAL),
+ ISTORE_W(0xc436, WIDE_LOCAL),
+ LSTORE_W(0xc437, WIDE_LOCAL),
+ FSTORE_W(0xc438, WIDE_LOCAL),
+ DSTORE_W(0xc439, WIDE_LOCAL),
+ ASTORE_W(0xc43a, WIDE_LOCAL),
+ IINC_W(0xc484, WIDE_LOCAL_SHORT),
+ RET_W(0xc4a9, WIDE_LOCAL),
// PicoJava nonpriv instructions
LOAD_UBYTE(PICOJAVA, 0xfe00),
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Mon Dec 10 20:59:38 2012 -0800
@@ -215,6 +215,9 @@
public boolean allowRepeatedAnnotations() {
return compareTo(JDK1_8) >= 0;
}
+ public boolean allowIntersectionTypesInCast() {
+ return compareTo(JDK1_8) >= 0;
+ }
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Mon Dec 10 20:59:38 2012 -0800
@@ -839,6 +839,49 @@
}
}
+ // a clone of a ClassType that knows about the bounds of an intersection type.
+ public static class IntersectionClassType extends ClassType implements IntersectionType {
+
+ public boolean allInterfaces;
+
+ public enum IntersectionKind {
+ EXPLICIT,
+ IMPLICT;
+ }
+
+ public IntersectionKind intersectionKind;
+
+ public IntersectionClassType(List<Type> bounds, ClassSymbol csym, boolean allInterfaces) {
+ super(Type.noType, List.<Type>nil(), csym);
+ this.allInterfaces = allInterfaces;
+ Assert.check((csym.flags() & COMPOUND) != 0);
+ supertype_field = bounds.head;
+ interfaces_field = bounds.tail;
+ Assert.check(supertype_field.tsym.completer != null ||
+ !supertype_field.isInterface(), supertype_field);
+ }
+
+ public java.util.List<? extends TypeMirror> getBounds() {
+ return Collections.unmodifiableList(getComponents());
+ }
+
+ public List<Type> getComponents() {
+ return interfaces_field.prepend(supertype_field);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.INTERSECTION;
+ }
+
+ @Override
+ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+ return intersectionKind == IntersectionKind.EXPLICIT ?
+ v.visitIntersection(this, p) :
+ v.visitDeclared(this, p);
+ }
+ }
+
public static class ArrayType extends Type
implements javax.lang.model.type.ArrayType {
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Dec 10 20:59:38 2012 -0800
@@ -26,7 +26,13 @@
package com.sun.tools.javac.code;
import java.lang.ref.SoftReference;
-import java.util.*;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Lint.LintCategory;
@@ -383,28 +389,6 @@
}
/**
- * Scope filter used to skip methods that should be ignored during
- * function interface conversion (such as methods overridden by
- * j.l.Object)
- */
- class DescriptorFilter implements Filter<Symbol> {
-
- TypeSymbol origin;
-
- DescriptorFilter(TypeSymbol origin) {
- this.origin = origin;
- }
-
- @Override
- public boolean accepts(Symbol sym) {
- return sym.kind == Kinds.MTH &&
- (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT &&
- !overridesObjectMethod(origin, sym) &&
- (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0;
- }
- };
-
- /**
* Compute the function descriptor associated with a given functional interface
*/
public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
@@ -431,23 +415,8 @@
throw failure("not.a.functional.intf.1",
diags.fragment("no.abstracts", Kinds.kindName(origin), origin));
} else if (abstracts.size() == 1) {
- if (abstracts.first().type.tag == FORALL) {
- throw failure("invalid.generic.desc.in.functional.intf",
- abstracts.first(),
- Kinds.kindName(origin),
- origin);
- } else {
- return new FunctionDescriptor(abstracts.first());
- }
+ return new FunctionDescriptor(abstracts.first());
} else { // size > 1
- for (Symbol msym : abstracts) {
- if (msym.type.tag == FORALL) {
- throw failure("invalid.generic.desc.in.functional.intf",
- abstracts.first(),
- Kinds.kindName(origin),
- origin);
- }
- }
FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList());
if (descRes == null) {
//we can get here if the functional interface is ill-formed
@@ -586,6 +555,85 @@
}
// </editor-fold>
+ /**
+ * Scope filter used to skip methods that should be ignored (such as methods
+ * overridden by j.l.Object) during function interface conversion/marker interface checks
+ */
+ class DescriptorFilter implements Filter<Symbol> {
+
+ TypeSymbol origin;
+
+ DescriptorFilter(TypeSymbol origin) {
+ this.origin = origin;
+ }
+
+ @Override
+ public boolean accepts(Symbol sym) {
+ return sym.kind == Kinds.MTH &&
+ (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT &&
+ !overridesObjectMethod(origin, sym) &&
+ (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0;
+ }
+ };
+
+ // <editor-fold defaultstate="collapsed" desc="isMarker">
+
+ /**
+ * A cache that keeps track of marker interfaces
+ */
+ class MarkerCache {
+
+ private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>();
+
+ class Entry {
+ final boolean isMarkerIntf;
+ final int prevMark;
+
+ public Entry(boolean isMarkerIntf,
+ int prevMark) {
+ this.isMarkerIntf = isMarkerIntf;
+ this.prevMark = prevMark;
+ }
+
+ boolean matches(int mark) {
+ return this.prevMark == mark;
+ }
+ }
+
+ boolean get(TypeSymbol origin) throws FunctionDescriptorLookupError {
+ Entry e = _map.get(origin);
+ CompoundScope members = membersClosure(origin.type, false);
+ if (e == null ||
+ !e.matches(members.getMark())) {
+ boolean isMarkerIntf = isMarkerInterfaceInternal(origin, members);
+ _map.put(origin, new Entry(isMarkerIntf, members.getMark()));
+ return isMarkerIntf;
+ }
+ else {
+ return e.isMarkerIntf;
+ }
+ }
+
+ /**
+ * Is given symbol a marker interface
+ */
+ public boolean isMarkerInterfaceInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
+ return !origin.isInterface() ?
+ false :
+ !membersCache.getElements(new DescriptorFilter(origin)).iterator().hasNext();
+ }
+ }
+
+ private MarkerCache markerCache = new MarkerCache();
+
+ /**
+ * Is given type a marker interface?
+ */
+ public boolean isMarkerInterface(Type site) {
+ return markerCache.get(site.tsym);
+ }
+ // </editor-fold>
+
// <editor-fold defaultstate="collapsed" desc="isSubtype">
/**
* Is t an unchecked subtype of s?
@@ -1964,45 +2012,28 @@
* @param supertype is objectType if all bounds are interfaces,
* null otherwise.
*/
- public Type makeCompoundType(List<Type> bounds,
- Type supertype) {
+ public Type makeCompoundType(List<Type> bounds) {
+ return makeCompoundType(bounds, bounds.head.tsym.isInterface());
+ }
+ public Type makeCompoundType(List<Type> bounds, boolean allInterfaces) {
+ Assert.check(bounds.nonEmpty());
+ Type firstExplicitBound = bounds.head;
+ if (allInterfaces) {
+ bounds = bounds.prepend(syms.objectType);
+ }
ClassSymbol bc =
new ClassSymbol(ABSTRACT|PUBLIC|SYNTHETIC|COMPOUND|ACYCLIC,
Type.moreInfo
? names.fromString(bounds.toString())
: names.empty,
+ null,
syms.noSymbol);
- if (bounds.head.tag == TYPEVAR)
- // error condition, recover
- bc.erasure_field = syms.objectType;
- else
- bc.erasure_field = erasure(bounds.head);
- bc.members_field = new Scope(bc);
- ClassType bt = (ClassType)bc.type;
- bt.allparams_field = List.nil();
- if (supertype != null) {
- bt.supertype_field = supertype;
- bt.interfaces_field = bounds;
- } else {
- bt.supertype_field = bounds.head;
- bt.interfaces_field = bounds.tail;
- }
- Assert.check(bt.supertype_field.tsym.completer != null
- || !bt.supertype_field.isInterface(),
- bt.supertype_field);
- return bt;
- }
-
- /**
- * Same as {@link #makeCompoundType(List,Type)}, except that the
- * second parameter is computed directly. Note that this might
- * cause a symbol completion. Hence, this version of
- * makeCompoundType may not be called during a classfile read.
- */
- public Type makeCompoundType(List<Type> bounds) {
- Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ?
- supertype(bounds.head) : null;
- return makeCompoundType(bounds, supertype);
+ bc.type = new IntersectionClassType(bounds, bc, allInterfaces);
+ bc.erasure_field = (bounds.head.tag == TYPEVAR) ?
+ syms.objectType : // error condition, recover
+ erasure(firstExplicitBound);
+ bc.members_field = new Scope(bc);
+ return bc.type;
}
/**
@@ -2192,12 +2223,8 @@
* @param supertype is objectType if all bounds are interfaces,
* null otherwise.
*/
- public void setBounds(TypeVar t, List<Type> bounds, Type supertype) {
- if (bounds.tail.isEmpty())
- t.bound = bounds.head;
- else
- t.bound = makeCompoundType(bounds, supertype);
- t.rank_field = -1;
+ public void setBounds(TypeVar t, List<Type> bounds) {
+ setBounds(t, bounds, bounds.head.tsym.isInterface());
}
/**
@@ -2209,10 +2236,10 @@
* Note that this check might cause a symbol completion. Hence, this version of
* setBounds may not be called during a classfile read.
*/
- public void setBounds(TypeVar t, List<Type> bounds) {
- Type supertype = (bounds.head.tsym.flags() & INTERFACE) != 0 ?
- syms.objectType : null;
- setBounds(t, bounds, supertype);
+ public void setBounds(TypeVar t, List<Type> bounds, boolean allInterfaces) {
+ t.bound = bounds.tail.isEmpty() ?
+ bounds.head :
+ makeCompoundType(bounds, allInterfaces);
t.rank_field = -1;
}
// </editor-fold>
@@ -2222,7 +2249,7 @@
* Return list of bounds of the given type variable.
*/
public List<Type> getBounds(TypeVar t) {
- if (t.bound.hasTag(NONE))
+ if (t.bound.hasTag(NONE))
return List.nil();
else if (t.bound.isErroneous() || !t.bound.isCompound())
return List.of(t.bound);
@@ -3321,8 +3348,7 @@
if (arraySuperType == null) {
// JLS 10.8: all arrays implement Cloneable and Serializable.
arraySuperType = makeCompoundType(List.of(syms.serializableType,
- syms.cloneableType),
- syms.objectType);
+ syms.cloneableType), true);
}
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Dec 10 20:59:38 2012 -0800
@@ -716,21 +716,8 @@
}
a.tsym.flags_field &= ~UNATTRIBUTED;
}
- for (JCTypeParameter tvar : typarams)
+ for (JCTypeParameter tvar : typarams) {
chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type);
- attribStats(typarams, env);
- }
-
- void attribBounds(List<JCTypeParameter> typarams) {
- for (JCTypeParameter typaram : typarams) {
- Type bound = typaram.type.getUpperBound();
- if (bound != null && bound.tsym instanceof ClassSymbol) {
- ClassSymbol c = (ClassSymbol)bound.tsym;
- if ((c.flags_field & COMPOUND) != 0) {
- Assert.check((c.flags_field & UNATTRIBUTED) != 0, c);
- attribClass(typaram.pos(), c);
- }
- }
}
}
@@ -892,7 +879,12 @@
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), m);
- attribBounds(tree.typarams);
+ // Create a new environment with local scope
+ // for attributing the method.
+ Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env);
+ localEnv.info.lint = lint;
+
+ attribStats(tree.typarams, localEnv);
// If we override any other methods, check that we do so properly.
// JLS ???
@@ -903,12 +895,6 @@
}
chk.checkOverride(tree, m);
- // Create a new environment with local scope
- // for attributing the method.
- Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env);
-
- localEnv.info.lint = lint;
-
if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) {
log.error(tree, "default.overrides.object.member", m.name, Kinds.kindName(m.location()), m.location());
}
@@ -2196,7 +2182,7 @@
Type target;
Type lambdaType;
if (pt() != Type.recoveryType) {
- target = infer.instantiateFunctionalInterface(that, pt(), explicitParamTypes, resultInfo.checkContext);
+ target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), explicitParamTypes, resultInfo.checkContext);
lambdaType = types.findDescriptorType(target);
chk.checkFunctionalInterface(that, target);
} else {
@@ -2204,6 +2190,14 @@
lambdaType = fallbackDescriptorType(that);
}
+ if (lambdaType.hasTag(FORALL)) {
+ //lambda expression target desc cannot be a generic method
+ resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
+ lambdaType, kindName(target.tsym), target.tsym));
+ result = that.type = types.createErrorType(pt());
+ return;
+ }
+
if (!TreeInfo.isExplicitLambda(that)) {
//add param type info in the AST
List<Type> actuals = lambdaType.getParameterTypes();
@@ -2244,9 +2238,13 @@
//with the target-type, it will be recovered anyway in Attr.checkId
needsRecovery = false;
+ FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
+ new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
+ new FunctionalReturnContext(resultInfo.checkContext);
+
ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
recoveryInfo :
- new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext));
+ new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
localEnv.info.returnResult = bodyResultInfo;
if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
@@ -2282,6 +2280,26 @@
}
}
}
+
+ private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) {
+ Type pt = resultInfo.pt;
+ if (pt != Type.recoveryType && pt.isCompound()) {
+ IntersectionClassType ict = (IntersectionClassType)pt;
+ List<Type> bounds = ict.allInterfaces ?
+ ict.getComponents().tail :
+ ict.getComponents();
+ types.findDescriptorType(bounds.head); //propagate exception outwards!
+ for (Type bound : bounds.tail) {
+ if (!types.isMarkerInterface(bound)) {
+ resultInfo.checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound));
+ }
+ }
+ //for now (translation doesn't support intersection types)
+ return bounds.head;
+ } else {
+ return pt;
+ }
+ }
//where
private Type fallbackDescriptorType(JCExpression tree) {
switch (tree.getTag()) {
@@ -2327,8 +2345,9 @@
* type according to both the inherited context and the assignment
* context.
*/
- class LambdaReturnContext extends Check.NestedCheckContext {
- public LambdaReturnContext(CheckContext enclosingContext) {
+ class FunctionalReturnContext extends Check.NestedCheckContext {
+
+ FunctionalReturnContext(CheckContext enclosingContext) {
super(enclosingContext);
}
@@ -2344,6 +2363,23 @@
}
}
+ class ExpressionLambdaReturnContext extends FunctionalReturnContext {
+
+ JCExpression expr;
+
+ ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
+ super(enclosingContext);
+ this.expr = expr;
+ }
+
+ @Override
+ public boolean compatible(Type found, Type req, Warner warn) {
+ //a void return is compatible with an expression statement lambda
+ return TreeInfo.isExpressionStatement(expr) && req.hasTag(VOID) ||
+ super.compatible(found, req, warn);
+ }
+ }
+
/**
* Lambda compatibility. Check that given return types, thrown types, parameter types
* are compatible with the expected functional interface descriptor. This means that:
@@ -2428,7 +2464,7 @@
}
//attrib type-arguments
- List<Type> typeargtypes = null;
+ List<Type> typeargtypes = List.nil();
if (that.typeargs != null) {
typeargtypes = attribTypes(that.typeargs, localEnv);
}
@@ -2436,7 +2472,7 @@
Type target;
Type desc;
if (pt() != Type.recoveryType) {
- target = infer.instantiateFunctionalInterface(that, pt(), null, resultInfo.checkContext);
+ target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), null, resultInfo.checkContext);
desc = types.findDescriptorType(target);
chk.checkFunctionalInterface(that, target);
} else {
@@ -2498,6 +2534,26 @@
}
}
+ if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
+ if (refSym.isStatic() && TreeInfo.isStaticSelector(that.expr, names) &&
+ exprType.getTypeArguments().nonEmpty()) {
+ //static ref with class type-args
+ log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
+ diags.fragment("static.mref.with.targs"));
+ result = that.type = types.createErrorType(target);
+ return;
+ }
+
+ if (refSym.isStatic() && !TreeInfo.isStaticSelector(that.expr, names) &&
+ !lookupHelper.referenceKind(refSym).isUnbound()) {
+ //no static bound mrefs
+ log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
+ diags.fragment("static.bound.mref"));
+ result = that.type = types.createErrorType(target);
+ return;
+ }
+ }
+
if (desc.getReturnType() == Type.recoveryType) {
// stop here
result = that.type = target;
@@ -2560,7 +2616,7 @@
if (!returnType.hasTag(VOID) && !resType.hasTag(VOID)) {
if (resType.isErroneous() ||
- new LambdaReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
+ new FunctionalReturnContext(checkContext).compatible(resType, returnType, types.noWarnings)) {
incompatibleReturnType = null;
}
}
@@ -3525,63 +3581,79 @@
tree.type = result = t;
}
- public void visitTypeParameter(JCTypeParameter tree) {
- TypeVar a = (TypeVar)tree.type;
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ attribTypes(tree.bounds, env);
+ tree.type = result = checkIntersection(tree, tree.bounds);
+ }
+
+ public void visitTypeParameter(JCTypeParameter tree) {
+ TypeVar typeVar = (TypeVar)tree.type;
+ if (!typeVar.bound.isErroneous()) {
+ //fixup type-parameter bound computed in 'attribTypeVariables'
+ typeVar.bound = checkIntersection(tree, tree.bounds);
+ }
+ }
+
+ Type checkIntersection(JCTree tree, List<JCExpression> bounds) {
Set<Type> boundSet = new HashSet<Type>();
- if (a.bound.isErroneous())
- return;
- List<Type> bs = types.getBounds(a);
- if (tree.bounds.nonEmpty()) {
+ if (bounds.nonEmpty()) {
// accept class or interface or typevar as first bound.
- Type b = checkBase(bs.head, tree.bounds.head, env, false, false, false);
- boundSet.add(types.erasure(b));
- if (b.isErroneous()) {
- a.bound = b;
+ bounds.head.type = checkBase(bounds.head.type, bounds.head, env, false, false, false);
+ boundSet.add(types.erasure(bounds.head.type));
+ if (bounds.head.type.isErroneous()) {
+ return bounds.head.type;
}
- else if (b.hasTag(TYPEVAR)) {
+ else if (bounds.head.type.hasTag(TYPEVAR)) {
// if first bound was a typevar, do not accept further bounds.
- if (tree.bounds.tail.nonEmpty()) {
- log.error(tree.bounds.tail.head.pos(),
+ if (bounds.tail.nonEmpty()) {
+ log.error(bounds.tail.head.pos(),
"type.var.may.not.be.followed.by.other.bounds");
- tree.bounds = List.of(tree.bounds.head);
- a.bound = bs.head;
+ return bounds.head.type;
}
} else {
// if first bound was a class or interface, accept only interfaces
// as further bounds.
- for (JCExpression bound : tree.bounds.tail) {
- bs = bs.tail;
- Type i = checkBase(bs.head, bound, env, false, true, false);
- if (i.isErroneous())
- a.bound = i;
- else if (i.hasTag(CLASS))
- chk.checkNotRepeated(bound.pos(), types.erasure(i), boundSet);
+ for (JCExpression bound : bounds.tail) {
+ bound.type = checkBase(bound.type, bound, env, false, true, false);
+ if (bound.type.isErroneous()) {
+ bounds = List.of(bound);
+ }
+ else if (bound.type.hasTag(CLASS)) {
+ chk.checkNotRepeated(bound.pos(), types.erasure(bound.type), boundSet);
+ }
}
}
}
- bs = types.getBounds(a);
-
- // in case of multiple bounds ...
- if (bs.length() > 1) {
+
+ if (bounds.length() == 0) {
+ return syms.objectType;
+ } else if (bounds.length() == 1) {
+ return bounds.head.type;
+ } else {
+ Type owntype = types.makeCompoundType(TreeInfo.types(bounds));
+ if (tree.hasTag(TYPEINTERSECTION)) {
+ ((IntersectionClassType)owntype).intersectionKind =
+ IntersectionClassType.IntersectionKind.EXPLICIT;
+ }
// ... the variable's bound is a class type flagged COMPOUND
// (see comment for TypeVar.bound).
// In this case, generate a class tree that represents the
// bound class, ...
JCExpression extending;
List<JCExpression> implementing;
- if ((bs.head.tsym.flags() & INTERFACE) == 0) {
- extending = tree.bounds.head;
- implementing = tree.bounds.tail;
+ if (!bounds.head.type.isInterface()) {
+ extending = bounds.head;
+ implementing = bounds.tail;
} else {
extending = null;
- implementing = tree.bounds;
+ implementing = bounds;
}
- JCClassDecl cd = make.at(tree.pos).ClassDef(
+ JCClassDecl cd = make.at(tree).ClassDef(
make.Modifiers(PUBLIC | ABSTRACT),
- tree.name, List.<JCTypeParameter>nil(),
+ names.empty, List.<JCTypeParameter>nil(),
extending, implementing, List.<JCTree>nil());
- ClassSymbol c = (ClassSymbol)a.getUpperBound().tsym;
+ ClassSymbol c = (ClassSymbol)owntype.tsym;
Assert.check((c.flags() & COMPOUND) != 0);
cd.sym = c;
c.sourcefile = env.toplevel.sourcefile;
@@ -3590,10 +3662,11 @@
c.flags_field |= UNATTRIBUTED;
Env<AttrContext> cenv = enter.classEnv(cd, env);
enter.typeEnvs.put(c, cenv);
+ attribClass(c);
+ return owntype;
}
}
-
public void visitWildcard(JCWildcard tree) {
//- System.err.println("visitWildcard("+tree+");");//DEBUG
Type type = (tree.kind.kind == BoundKind.UNBOUND)
@@ -3747,7 +3820,7 @@
chk.validateAnnotations(tree.mods.annotations, c);
// Validate type parameters, supertype and interfaces.
- attribBounds(tree.typarams);
+ attribStats(tree.typarams, env);
if (!c.isAnonymous()) {
//already checked if anonymous
chk.validate(tree.typarams, env);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Dec 10 20:59:38 2012 -0800
@@ -288,21 +288,20 @@
JCExpression init;
switch(tree.kind) {
- case IMPLICIT_INNER: /** Inner # new */
- case SUPER: /** super # instMethod */
+ case IMPLICIT_INNER: /** Inner :: new */
+ case SUPER: /** super :: instMethod */
init = makeThis(
localContext.owner.owner.asType(),
localContext.owner);
break;
- case BOUND: /** Expr # instMethod */
+ case BOUND: /** Expr :: instMethod */
init = tree.getQualifierExpression();
break;
- case STATIC_EVAL: /** Expr # staticMethod */
- case UNBOUND: /** Type # instMethod */
- case STATIC: /** Type # staticMethod */
- case TOPLEVEL: /** Top level # new */
+ case UNBOUND: /** Type :: instMethod */
+ case STATIC: /** Type :: staticMethod */
+ case TOPLEVEL: /** Top level :: new */
init = null;
break;
@@ -315,14 +314,6 @@
//build a sam instance using an indy call to the meta-factory
result = makeMetaFactoryIndyCall(tree, tree.targetType, localContext.referenceKind(), refSym, indy_args);
-
- //if we had a static reference with non-static qualifier, add a let
- //expression to force the evaluation of the qualifier expr
- if (tree.hasKind(ReferenceKind.STATIC_EVAL)) {
- VarSymbol rec = new VarSymbol(0, names.fromString("rec$"), tree.getQualifierExpression().type, localContext.owner);
- JCVariableDecl recDef = make.VarDef(rec, tree.getQualifierExpression());
- result = make.LetExpr(recDef, result).setType(tree.type);
- }
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Mon Dec 10 20:59:38 2012 -0800
@@ -138,6 +138,10 @@
*/
Map<ClassSymbol, JCClassDecl> classdefs;
+ /** A hash table mapping local classes to a list of pruned trees.
+ */
+ public Map<ClassSymbol, List<JCTree>> prunedTree = new WeakHashMap<ClassSymbol, List<JCTree>>();
+
/** A hash table mapping virtual accessed symbols in outer subclasses
* to the actually referred symbol in superclasses.
*/
@@ -1039,6 +1043,12 @@
}
}
+ private void addPrunedInfo(JCTree tree) {
+ List<JCTree> infoList = prunedTree.get(currentClass);
+ infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
+ prunedTree.put(currentClass, infoList);
+ }
+
/** Ensure that identifier is accessible, return tree accessing the identifier.
* @param sym The accessed symbol.
* @param tree The tree referring to the symbol.
@@ -1111,7 +1121,10 @@
// Constants are replaced by their constant value.
if (sym.kind == VAR) {
Object cv = ((VarSymbol)sym).getConstValue();
- if (cv != null) return makeLit(sym.type, cv);
+ if (cv != null) {
+ addPrunedInfo(tree);
+ return makeLit(sym.type, cv);
+ }
}
// Private variables and methods are replaced by calls
@@ -2746,12 +2759,15 @@
/** Visitor method for conditional expressions.
*/
+ @Override
public void visitConditional(JCConditional tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
result = convert(translate(tree.truepart, tree.type), tree.type);
+ addPrunedInfo(cond);
} else if (cond.type.isFalse()) {
result = convert(translate(tree.falsepart, tree.type), tree.type);
+ addPrunedInfo(cond);
} else {
// Condition is not a compile-time constant.
tree.truepart = translate(tree.truepart, tree.type);
@@ -2760,14 +2776,14 @@
}
}
//where
- private JCTree convert(JCTree tree, Type pt) {
- if (tree.type == pt || tree.type.hasTag(BOT))
- return tree;
- JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
- result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
- : pt;
- return result;
- }
+ private JCTree convert(JCTree tree, Type pt) {
+ if (tree.type == pt || tree.type.hasTag(BOT))
+ return tree;
+ JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
+ result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
+ : pt;
+ return result;
+ }
/** Visitor method for if statements.
*/
@@ -2775,12 +2791,14 @@
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
result = translate(tree.thenpart);
+ addPrunedInfo(cond);
} else if (cond.type.isFalse()) {
if (tree.elsepart != null) {
result = translate(tree.elsepart);
} else {
result = make.Skip();
}
+ addPrunedInfo(cond);
} else {
// Condition is not a compile-time constant.
tree.thenpart = translate(tree.thenpart);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Dec 10 20:59:38 2012 -0800
@@ -2617,8 +2617,7 @@
@Override
ReferenceKind referenceKind(Symbol sym) {
if (sym.isStatic()) {
- return TreeInfo.isStaticSelector(referenceTree.expr, names) ?
- ReferenceKind.STATIC : ReferenceKind.STATIC_EVAL;
+ return ReferenceKind.STATIC;
} else {
Name selName = TreeInfo.name(referenceTree.getQualifierExpression());
return selName != null && selName == names._super ?
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Mon Dec 10 20:59:38 2012 -0800
@@ -551,6 +551,7 @@
tree.body = translate(tree.body, null);
//save non-erased target
tree.targetType = tree.type;
+ Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
tree.type = erasure(tree.type);
result = tree;
}
@@ -786,6 +787,7 @@
tree.expr = translate(tree.expr, null);
//save non-erased target
tree.targetType = tree.type;
+ Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
tree.type = erasure(tree.type);
result = tree;
}
@@ -803,6 +805,12 @@
result = clazz;
}
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ tree.bounds = translate(tree.bounds, null);
+ tree.type = erasure(tree.type);
+ result = tree;
+ }
+
/**************************************************************************
* utility methods
*************************************************************************/
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Dec 10 20:59:38 2012 -0800
@@ -846,17 +846,17 @@
tvar = (TypeVar)findTypeVar(name);
}
List<Type> bounds = List.nil();
- Type st = null;
+ boolean allInterfaces = false;
if (signature[sigp] == ':' && signature[sigp+1] == ':') {
sigp++;
- st = syms.objectType;
+ allInterfaces = true;
}
while (signature[sigp] == ':') {
sigp++;
bounds = bounds.prepend(sigToType());
}
if (!sigEnterPhase) {
- types.setBounds(tvar, bounds.reverse(), st);
+ types.setBounds(tvar, bounds.reverse(), allInterfaces);
}
return tvar;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Mon Dec 10 20:59:38 2012 -0800
@@ -71,6 +71,7 @@
private final Map<Type,Symbol> stringBufferAppend;
private Name accessDollar;
private final Types types;
+ private final Lower lower;
/** Switch: GJ mode?
*/
@@ -112,6 +113,7 @@
stringBufferAppend = new HashMap<Type,Symbol>();
accessDollar = names.
fromString("access" + target.syntheticNameChar());
+ lower = Lower.instance(context);
Options options = Options.instance(context);
lineDebugInfo =
@@ -816,6 +818,62 @@
}
}
+ /** Visitor class for expressions which might be constant expressions.
+ * This class is a subset of TreeScanner. Intended to visit trees pruned by
+ * Lower as long as constant expressions looking for references to any
+ * ClassSymbol. Any such reference will be added to the constant pool so
+ * automated tools can detect class dependencies better.
+ */
+ class ClassReferenceVisitor extends JCTree.Visitor {
+
+ @Override
+ public void visitTree(JCTree tree) {}
+
+ @Override
+ public void visitBinary(JCBinary tree) {
+ tree.lhs.accept(this);
+ tree.rhs.accept(this);
+ }
+
+ @Override
+ public void visitSelect(JCFieldAccess tree) {
+ if (tree.selected.type.hasTag(CLASS)) {
+ makeRef(tree.selected.pos(), tree.selected.type);
+ }
+ }
+
+ @Override
+ public void visitIdent(JCIdent tree) {
+ if (tree.sym.owner instanceof ClassSymbol) {
+ pool.put(tree.sym.owner);
+ }
+ }
+
+ @Override
+ public void visitConditional(JCConditional tree) {
+ tree.cond.accept(this);
+ tree.truepart.accept(this);
+ tree.falsepart.accept(this);
+ }
+
+ @Override
+ public void visitUnary(JCUnary tree) {
+ tree.arg.accept(this);
+ }
+
+ @Override
+ public void visitParens(JCParens tree) {
+ tree.expr.accept(this);
+ }
+
+ @Override
+ public void visitTypeCast(JCTypeCast tree) {
+ tree.expr.accept(this);
+ }
+ }
+
+ private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor();
+
/** Visitor method: generate code for an expression, catching and reporting
* any completion failures.
* @param tree The expression to be visited.
@@ -826,6 +884,7 @@
try {
if (tree.type.constValue() != null) {
// Short circuit any expressions which are constants
+ tree.accept(classReferenceVisitor);
checkStringConstant(tree.pos(), tree.type.constValue());
result = items.makeImmediateItem(tree.type, tree.type.constValue());
} else {
@@ -2205,6 +2264,15 @@
code.endScopes(limit);
}
+ private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
+ List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol);
+ if (prunedInfo != null) {
+ for (JCTree prunedTree: prunedInfo) {
+ prunedTree.accept(classReferenceVisitor);
+ }
+ }
+ }
+
/* ************************************************************************
* main method
*************************************************************************/
@@ -2232,6 +2300,7 @@
cdef.defs = normalizeDefs(cdef.defs, c);
c.pool = pool;
pool.reset();
+ generateReferencesToPrunedTree(c, pool);
Env<GenContext> localEnv =
new Env<GenContext>(cdef, new GenContext());
localEnv.toplevel = env.toplevel;
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Mon Dec 10 20:59:38 2012 -0800
@@ -74,6 +74,7 @@
public Element asElement(TypeMirror t) {
switch (t.getKind()) {
case DECLARED:
+ case INTERSECTION:
case ERROR:
case TYPEVAR:
Type type = cast(Type.class, t);
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Mon Dec 10 20:59:38 2012 -0800
@@ -348,8 +348,8 @@
private void scanIdent() {
boolean isJavaIdentifierPart;
char high;
+ reader.putChar(true);
do {
- reader.putChar(true);
switch (reader.ch) {
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
@@ -366,6 +366,7 @@
case '$': case '_':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
+ break;
case '\u0000': case '\u0001': case '\u0002': case '\u0003':
case '\u0004': case '\u0005': case '\u0006': case '\u0007':
case '\u0008': case '\u000E': case '\u000F': case '\u0010':
@@ -373,26 +374,33 @@
case '\u0015': case '\u0016': case '\u0017':
case '\u0018': case '\u0019': case '\u001B':
case '\u007F':
- break;
+ reader.scanChar();
+ continue;
case '\u001A': // EOI is also a legal identifier part
if (reader.bp >= reader.buflen) {
name = reader.name();
tk = tokens.lookupKind(name);
return;
}
- break;
+ reader.scanChar();
+ continue;
default:
if (reader.ch < '\u0080') {
// all ASCII range chars already handled, above
isJavaIdentifierPart = false;
} else {
- high = reader.scanSurrogates();
- if (high != 0) {
- reader.putChar(high);
- isJavaIdentifierPart = Character.isJavaIdentifierPart(
- Character.toCodePoint(high, reader.ch));
+ if (Character.isIdentifierIgnorable(reader.ch)) {
+ reader.scanChar();
+ continue;
} else {
- isJavaIdentifierPart = Character.isJavaIdentifierPart(reader.ch);
+ high = reader.scanSurrogates();
+ if (high != 0) {
+ reader.putChar(high);
+ isJavaIdentifierPart = Character.isJavaIdentifierPart(
+ Character.toCodePoint(high, reader.ch));
+ } else {
+ isJavaIdentifierPart = Character.isJavaIdentifierPart(reader.ch);
+ }
}
}
if (!isJavaIdentifierPart) {
@@ -401,6 +409,7 @@
return;
}
}
+ reader.putChar(true);
} while (true);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Dec 10 20:59:38 2012 -0800
@@ -124,6 +124,9 @@
this.allowLambda = source.allowLambda();
this.allowMethodReferences = source.allowMethodReferences();
this.allowDefaultMethods = source.allowDefaultMethods();
+ this.allowIntersectionTypesInCast =
+ source.allowIntersectionTypesInCast() &&
+ fac.options.isSet("allowIntersectionTypes");
this.keepDocComments = keepDocComments;
docComments = newDocCommentTable(keepDocComments, fac);
this.keepLineMap = keepLineMap;
@@ -197,6 +200,10 @@
*/
boolean allowDefaultMethods;
+ /** Switch: should we allow intersection types in cast?
+ */
+ boolean allowIntersectionTypesInCast;
+
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
@@ -239,22 +246,38 @@
}
protected boolean peekToken(TokenKind tk) {
- return S.token(1).kind == tk;
+ return peekToken(0, tk);
+ }
+
+ protected boolean peekToken(int lookahead, TokenKind tk) {
+ return S.token(lookahead + 1).kind == tk;
}
protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
- return S.token(1).kind == tk1 &&
- S.token(2).kind == tk2;
+ return peekToken(0, tk1, tk2);
+ }
+
+ protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) {
+ return S.token(lookahead + 1).kind == tk1 &&
+ S.token(lookahead + 2).kind == tk2;
}
protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
- return S.token(1).kind == tk1 &&
- S.token(2).kind == tk2 &&
- S.token(3).kind == tk3;
+ return peekToken(0, tk1, tk2, tk3);
+ }
+
+ protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) {
+ return S.token(lookahead + 1).kind == tk1 &&
+ S.token(lookahead + 2).kind == tk2 &&
+ S.token(lookahead + 3).kind == tk3;
}
protected boolean peekToken(TokenKind... kinds) {
- for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
+ return peekToken(0, kinds);
+ }
+
+ protected boolean peekToken(int lookahead, TokenKind... kinds) {
+ for (; lookahead < kinds.length ; lookahead++) {
if (S.token(lookahead + 1).kind != kinds[lookahead]) {
return false;
}
@@ -966,102 +989,40 @@
break;
case LPAREN:
if (typeArgs == null && (mode & EXPR) != 0) {
- if (peekToken(MONKEYS_AT) ||
- peekToken(FINAL) ||
- peekToken(RPAREN) ||
- peekToken(IDENTIFIER, COMMA) ||
- peekToken(IDENTIFIER, RPAREN, ARROW)) {
- //implicit n-ary lambda
- t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
- break;
- } else {
- nextToken();
- mode = EXPR | TYPE | NOPARAMS;
- t = term3();
- if ((mode & TYPE) != 0 && token.kind == LT) {
- // Could be a cast to a parameterized type
- JCTree.Tag op = JCTree.Tag.LT;
- int pos1 = token.pos;
- nextToken();
- mode &= (EXPR | TYPE);
- mode |= TYPEARG;
- JCExpression t1 = term3();
- if ((mode & TYPE) != 0 &&
- (token.kind == COMMA || token.kind == GT)) {
- mode = TYPE;
- ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
- args.append(t1);
- while (token.kind == COMMA) {
- nextToken();
- args.append(typeArgument());
- }
- accept(GT);
- t = toP(F.at(pos1).TypeApply(t, args.toList()));
- checkGenerics();
- mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
- t = term3Rest(t, typeArgs);
- if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
- //explicit lambda (w/ generic type)
- mode = EXPR;
- JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
- if (token.kind == ELLIPSIS) {
- mods.flags = Flags.VARARGS;
- t = to(F.at(token.pos).TypeArray(t));
- nextToken();
- }
- t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
- break;
- }
- } else if ((mode & EXPR) != 0) {
- mode = EXPR;
- JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
- t = F.at(pos1).Binary(op, t, e);
- t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
- } else {
- accept(GT);
- }
- } else if ((mode & TYPE) != 0 &&
- (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
- //explicit lambda (w/ non-generic type)
+ ParensResult pres = analyzeParens();
+ switch (pres) {
+ case CAST:
+ accept(LPAREN);
+ mode = TYPE;
+ int pos1 = pos;
+ List<JCExpression> targets = List.of(t = term3());
+ while (token.kind == AMP) {
+ checkIntersectionTypesInCast();
+ accept(AMP);
+ targets = targets.prepend(term3());
+ }
+ if (targets.length() > 1) {
+ t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
+ }
+ accept(RPAREN);
+ mode = EXPR;
+ JCExpression t1 = term3();
+ return F.at(pos).TypeCast(t, t1);
+ case IMPLICIT_LAMBDA:
+ case EXPLICIT_LAMBDA:
+ t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
+ break;
+ default: //PARENS
+ accept(LPAREN);
mode = EXPR;
- JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
- if (token.kind == ELLIPSIS) {
- mods.flags = Flags.VARARGS;
- t = to(F.at(token.pos).TypeArray(t));
- nextToken();
- }
- t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+ t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
+ accept(RPAREN);
+ t = toP(F.at(pos).Parens(t));
break;
- } else {
- t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
- }
- }
-
- accept(RPAREN);
- lastmode = mode;
- mode = EXPR;
- if ((lastmode & EXPR) == 0) {
- JCExpression t1 = term3();
- return F.at(pos).TypeCast(t, t1);
- } else if ((lastmode & TYPE) != 0) {
- switch (token.kind) {
- /*case PLUSPLUS: case SUBSUB: */
- case BANG: case TILDE:
- case LPAREN: case THIS: case SUPER:
- case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
- case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
- case TRUE: case FALSE: case NULL:
- case NEW: case IDENTIFIER: case ASSERT: case ENUM:
- case BYTE: case SHORT: case CHAR: case INT:
- case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
- JCExpression t1 = term3();
- return F.at(pos).TypeCast(t, t1);
- }
}
} else {
return illegal();
}
- t = toP(F.at(pos).Parens(t));
break;
case THIS:
if ((mode & EXPR) != 0) {
@@ -1346,6 +1307,138 @@
}
}
+ /**
+ * If we see an identifier followed by a '<' it could be an unbound
+ * method reference or a binary expression. To disambiguate, look for a
+ * matching '>' and see if the subsequent terminal is either '.' or '#'.
+ */
+ @SuppressWarnings("fallthrough")
+ ParensResult analyzeParens() {
+ int depth = 0;
+ boolean type = false;
+ for (int lookahead = 0 ; ; lookahead++) {
+ TokenKind tk = S.token(lookahead).kind;
+ switch (tk) {
+ case EXTENDS: case SUPER: case COMMA:
+ type = true;
+ case QUES: case DOT: case AMP:
+ //skip
+ break;
+ case BYTE: case SHORT: case INT: case LONG: case FLOAT:
+ case DOUBLE: case BOOLEAN: case CHAR:
+ if (peekToken(lookahead, RPAREN)) {
+ //Type, ')' -> cast
+ return ParensResult.CAST;
+ } else if (peekToken(lookahead, IDENTIFIER)) {
+ //Type, 'Identifier -> explicit lambda
+ return ParensResult.EXPLICIT_LAMBDA;
+ }
+ break;
+ case LPAREN:
+ if (lookahead != 0) {
+ // '(' in a non-starting position -> parens
+ return ParensResult.PARENS;
+ } else if (peekToken(lookahead, RPAREN)) {
+ // '(', ')' -> explicit lambda
+ return ParensResult.EXPLICIT_LAMBDA;
+ }
+ break;
+ case RPAREN:
+ // if we have seen something that looks like a type,
+ // then it's a cast expression
+ if (type) return ParensResult.CAST;
+ // otherwise, disambiguate cast vs. parenthesized expression
+ // based on subsequent token.
+ switch (S.token(lookahead + 1).kind) {
+ /*case PLUSPLUS: case SUBSUB: */
+ case BANG: case TILDE:
+ case LPAREN: case THIS: case SUPER:
+ case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
+ case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
+ case TRUE: case FALSE: case NULL:
+ case NEW: case IDENTIFIER: case ASSERT: case ENUM:
+ case BYTE: case SHORT: case CHAR: case INT:
+ case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
+ return ParensResult.CAST;
+ default:
+ return ParensResult.PARENS;
+ }
+ case IDENTIFIER:
+ if (peekToken(lookahead, IDENTIFIER)) {
+ // Identifier, Identifier -> explicit lambda
+ return ParensResult.EXPLICIT_LAMBDA;
+ } else if (peekToken(lookahead, RPAREN, ARROW)) {
+ // Identifier, ')' '->' -> implicit lambda
+ return ParensResult.IMPLICIT_LAMBDA;
+ }
+ break;
+ case FINAL:
+ case ELLIPSIS:
+ case MONKEYS_AT:
+ //those can only appear in explicit lambdas
+ return ParensResult.EXPLICIT_LAMBDA;
+ case LBRACKET:
+ if (peekToken(lookahead, RBRACKET, IDENTIFIER)) {
+ // '[', ']', Identifier -> explicit lambda
+ return ParensResult.EXPLICIT_LAMBDA;
+ } else if (peekToken(lookahead, RBRACKET, RPAREN) ||
+ peekToken(lookahead, RBRACKET, AMP)) {
+ // '[', ']', ')' -> cast
+ // '[', ']', '&' -> cast (intersection type)
+ return ParensResult.CAST;
+ } else if (peekToken(lookahead, RBRACKET)) {
+ //consume the ']' and skip
+ type = true;
+ lookahead++;
+ break;
+ } else {
+ return ParensResult.PARENS;
+ }
+ case LT:
+ depth++; break;
+ case GTGTGT:
+ depth--;
+ case GTGT:
+ depth--;
+ case GT:
+ depth--;
+ if (depth == 0) {
+ if (peekToken(lookahead, RPAREN) ||
+ peekToken(lookahead, AMP)) {
+ // '>', ')' -> cast
+ // '>', '&' -> cast
+ return ParensResult.CAST;
+ } else if (peekToken(lookahead, IDENTIFIER, COMMA) ||
+ peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) ||
+ peekToken(lookahead, ELLIPSIS)) {
+ // '>', Identifier, ',' -> explicit lambda
+ // '>', Identifier, ')', '->' -> explicit lambda
+ // '>', '...' -> explicit lambda
+ return ParensResult.EXPLICIT_LAMBDA;
+ }
+ //it looks a type, but could still be (i) a cast to generic type,
+ //(ii) an unbound method reference or (iii) an explicit lambda
+ type = true;
+ break;
+ } else if (depth < 0) {
+ //unbalanced '<', '>' - not a generic type
+ return ParensResult.PARENS;
+ }
+ break;
+ default:
+ //this includes EOF
+ return ParensResult.PARENS;
+ }
+ }
+ }
+
+ enum ParensResult {
+ CAST,
+ EXPLICIT_LAMBDA,
+ IMPLICIT_LAMBDA,
+ PARENS;
+ }
+
JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
params.append(firstParam);
@@ -3171,21 +3264,12 @@
/** Check that given tree is a legal expression statement.
*/
protected JCExpression checkExprStat(JCExpression t) {
- switch(t.getTag()) {
- case PREINC: case PREDEC:
- case POSTINC: case POSTDEC:
- case ASSIGN:
- case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
- case SL_ASG: case SR_ASG: case USR_ASG:
- case PLUS_ASG: case MINUS_ASG:
- case MUL_ASG: case DIV_ASG: case MOD_ASG:
- case APPLY: case NEWCLASS:
- case ERRONEOUS:
- return t;
- default:
+ if (!TreeInfo.isExpressionStatement(t)) {
JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
error(ret, "not.stmt");
return ret;
+ } else {
+ return t;
}
}
@@ -3395,6 +3479,12 @@
allowDefaultMethods = true;
}
}
+ void checkIntersectionTypesInCast() {
+ if (!allowIntersectionTypesInCast) {
+ log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name);
+ allowIntersectionTypesInCast = true;
+ }
+ }
/*
* a functional source tree and end position mappings
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Dec 10 20:59:38 2012 -0800
@@ -187,8 +187,9 @@
{0}
# 0: symbol, 1: symbol kind, 2: symbol
-compiler.misc.invalid.generic.desc.in.functional.intf=\
- invalid functional descriptor: method {0} in {1} {2} is generic
+compiler.misc.invalid.generic.lambda.target=\
+ invalid functional descriptor for lambda expression\n\
+ method {0} in {1} {2} is generic
# 0: symbol kind, 1: symbol
compiler.misc.incompatible.descs.in.functional.intf=\
@@ -206,6 +207,10 @@
compiler.misc.no.suitable.functional.intf.inst=\
cannot infer functional interface descriptor for {0}
+# 0: type
+compiler.misc.secondary.bound.must.be.marker.intf=\
+ secondary bound {0} must be a marker interface
+
# 0: symbol kind, 1: message segment
compiler.err.invalid.mref=\
invalid {0} reference; {1}
@@ -214,6 +219,12 @@
compiler.misc.invalid.mref=\
invalid {0} reference; {1}
+compiler.misc.static.mref.with.targs=\
+ parameterized qualifier on static method reference
+
+compiler.misc.static.bound.mref=\
+ static bound method reference
+
# 0: symbol
compiler.err.cant.assign.val.to.final.var=\
cannot assign a value to final variable {0}
@@ -2196,6 +2207,11 @@
default methods are not supported in -source {0}\n\
(use -source 8 or higher to enable default methods)
+# 0: string
+compiler.err.intersection.types.in.cast.not.supported.in.source=\
+ intersection types in cast are not supported in -source {0}\n\
+ (use -source 8 or higher to enable default methods)
+
########################################
# Diagnostics for verbose resolution
# used by Resolve (debug only)
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Dec 10 20:59:38 2012 -0800
@@ -254,6 +254,10 @@
*/
TYPEUNION,
+ /** Intersection types, of type TypeIntersection
+ */
+ TYPEINTERSECTION,
+
/** Formal type parameters, of type TypeParameter.
*/
TYPEPARAMETER,
@@ -1829,8 +1833,6 @@
STATIC(ReferenceMode.INVOKE, false),
/** Expr # instMethod */
BOUND(ReferenceMode.INVOKE, false),
- /** Expr # staticMethod */
- STATIC_EVAL(ReferenceMode.INVOKE, false),
/** Inner # new */
IMPLICIT_INNER(ReferenceMode.NEW, false),
/** Toplevel # new */
@@ -2064,6 +2066,34 @@
}
/**
+ * An intersection type, T1 & T2 & ... Tn (used in cast expressions)
+ */
+ public static class JCTypeIntersection extends JCExpression implements IntersectionTypeTree {
+
+ public List<JCExpression> bounds;
+
+ protected JCTypeIntersection(List<JCExpression> bounds) {
+ this.bounds = bounds;
+ }
+ @Override
+ public void accept(Visitor v) { v.visitTypeIntersection(this); }
+
+ public Kind getKind() { return Kind.INTERSECTION_TYPE; }
+
+ public List<JCExpression> getBounds() {
+ return bounds;
+ }
+ @Override
+ public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+ return v.visitIntersectionType(this, d);
+ }
+ @Override
+ public Tag getTag() {
+ return TYPEINTERSECTION;
+ }
+ }
+
+ /**
* A formal class parameter.
*/
public static class JCTypeParameter extends JCTree implements TypeParameterTree {
@@ -2385,6 +2415,7 @@
public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); }
public void visitTypeApply(JCTypeApply that) { visitTree(that); }
public void visitTypeUnion(JCTypeUnion that) { visitTree(that); }
+ public void visitTypeIntersection(JCTypeIntersection that) { visitTree(that); }
public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
public void visitWildcard(JCWildcard that) { visitTree(that); }
public void visitTypeBoundKind(TypeBoundKind that) { visitTree(that); }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Mon Dec 10 20:59:38 2012 -0800
@@ -1249,6 +1249,14 @@
}
}
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ try {
+ printExprs(tree.bounds, " & ");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
public void visitTypeParameter(JCTypeParameter tree) {
try {
print(tree.name);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java Mon Dec 10 20:59:38 2012 -0800
@@ -358,6 +358,12 @@
return M.at(t.pos).TypeUnion(components);
}
+ public JCTree visitIntersectionType(IntersectionTypeTree node, P p) {
+ JCTypeIntersection t = (JCTypeIntersection) node;
+ List<JCExpression> bounds = copy(t.bounds, p);
+ return M.at(t.pos).TypeIntersection(bounds);
+ }
+
public JCTree visitArrayType(ArrayTypeTree node, P p) {
JCArrayTypeTree t = (JCArrayTypeTree) node;
JCExpression elemtype = copy(t.elemtype, p);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Dec 10 20:59:38 2012 -0800
@@ -267,6 +267,25 @@
return lambda.params.isEmpty() ||
lambda.params.head.vartype != null;
}
+
+ /** Return true if the tree corresponds to an expression statement */
+ public static boolean isExpressionStatement(JCExpression tree) {
+ switch(tree.getTag()) {
+ case PREINC: case PREDEC:
+ case POSTINC: case POSTDEC:
+ case ASSIGN:
+ case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
+ case SL_ASG: case SR_ASG: case USR_ASG:
+ case PLUS_ASG: case MINUS_ASG:
+ case MUL_ASG: case DIV_ASG: case MOD_ASG:
+ case APPLY: case NEWCLASS:
+ case ERRONEOUS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/**
* Return true if the AST corresponds to a static select of the kind A.B
*/
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Mon Dec 10 20:59:38 2012 -0800
@@ -456,6 +456,12 @@
return tree;
}
+ public JCTypeIntersection TypeIntersection(List<JCExpression> components) {
+ JCTypeIntersection tree = new JCTypeIntersection(components);
+ tree.pos = pos;
+ return tree;
+ }
+
public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) {
JCTypeParameter tree = new JCTypeParameter(name, bounds);
tree.pos = pos;
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java Mon Dec 10 20:59:38 2012 -0800
@@ -286,6 +286,10 @@
scan(tree.alternatives);
}
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ scan(tree.bounds);
+ }
+
public void visitTypeParameter(JCTypeParameter tree) {
scan(tree.bounds);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java Mon Dec 10 20:59:38 2012 -0800
@@ -379,6 +379,11 @@
result = tree;
}
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ tree.bounds = translate(tree.bounds);
+ result = tree;
+ }
+
public void visitTypeParameter(JCTypeParameter tree) {
tree.bounds = translate(tree.bounds);
result = tree;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/javax/lang/model/type/IntersectionType.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.lang.model.type;
+
+import java.util.List;
+
+/**
+ * Represents an intersection type.
+ *
+ * As of the {@link javax.lang.model.SourceVersion#RELEASE_8
+ * RELEASE_8} source version, intersection types can appear as the target type
+ * of a cast expression.
+ *
+ * @since 1.8
+ */
+public interface IntersectionType extends TypeMirror {
+
+ /**
+ * Return the bounds comprising this intersection type.
+ *
+ * @return the bounds of this intersection types.
+ */
+ List<? extends TypeMirror> getBounds();
+}
--- a/langtools/src/share/classes/javax/lang/model/type/TypeKind.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/javax/lang/model/type/TypeKind.java Mon Dec 10 20:59:38 2012 -0800
@@ -144,7 +144,14 @@
*
* @since 1.7
*/
- UNION;
+ UNION,
+
+ /**
+ * An intersection type.
+ *
+ * @since 1.8
+ */
+ INTERSECTION;
/**
* Returns {@code true} if this kind corresponds to a primitive
--- a/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/javax/lang/model/type/TypeVisitor.java Mon Dec 10 20:59:38 2012 -0800
@@ -172,4 +172,14 @@
* @since 1.7
*/
R visitUnion(UnionType t, P p);
+
+ /**
+ * Visits an intersection type.
+ *
+ * @param t the type to visit
+ * @param p a visitor-specified parameter
+ * @return a visitor-specified result
+ * @since 1.8
+ */
+ R visitIntersection(IntersectionType t, P p);
}
--- a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor6.java Mon Dec 10 20:59:38 2012 -0800
@@ -111,6 +111,20 @@
}
/**
+ * Visits an {@code IntersectionType} element by calling {@code
+ * visitUnknown}.
+
+ * @param t {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of {@code visitUnknown}
+ *
+ * @since 1.8
+ */
+ public R visitIntersection(IntersectionType t, P p) {
+ return visitUnknown(t, p);
+ }
+
+ /**
* {@inheritDoc}
*
* <p> The default implementation of this method in {@code
--- a/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/javax/lang/model/util/AbstractTypeVisitor8.java Mon Dec 10 20:59:38 2012 -0800
@@ -66,4 +66,13 @@
protected AbstractTypeVisitor8() {
super();
}
+
+ /**
+ * Visits an {@code IntersectionType} in a manner defined by a subclass.
+ *
+ * @param t {@inheritDoc}
+ * @param p {@inheritDoc}
+ * @return the result of the visit as defined by a subclass
+ */
+ public abstract R visitIntersection(IntersectionType t, P p);
}
--- a/langtools/src/share/classes/javax/tools/JavaCompiler.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/src/share/classes/javax/tools/JavaCompiler.java Mon Dec 10 20:59:38 2012 -0800
@@ -108,8 +108,8 @@
* example a recommended coding pattern:
*
* <pre>
- * Files[] files1 = ... ; // input for first compilation task
- * Files[] files2 = ... ; // input for second compilation task
+ * File[] files1 = ... ; // input for first compilation task
+ * File[] files2 = ... ; // input for second compilation task
*
* JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
* StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
@@ -165,7 +165,7 @@
* JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
* StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
* JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) {
- * public void flush() {
+ * public void flush() throws IOException {
* logger.entering(StandardJavaFileManager.class.getName(), "flush");
* super.flush();
* logger.exiting(StandardJavaFileManager.class.getName(), "flush");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7144981/IgnoreIgnorableCharactersInInput.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,92 @@
+
+/*
+ * @test /nodynamiccopyright/
+ * @bug 7144981
+ * @summary javac should ignore ignorable characters in input
+ * @run main IgnoreIgnorableCharactersInInput
+ */
+
+import com.sun.source.util.JavacTask;
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class IgnoreIgnorableCharactersInInput {
+
+ public static void main(String... args) throws Exception {
+ new IgnoreIgnorableCharactersInInput().run();
+ }
+
+ void run() throws Exception {
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ File classesDir = new File(System.getProperty("user.dir"), "classes");
+ classesDir.mkdirs();
+ JavaSource[] sources = new JavaSource[]{
+ new JavaSource("TestOneIgnorableChar", "AA\\u0000BB"),
+ new JavaSource("TestMultipleIgnorableChar", "AA\\u0000\\u0000\\u0000BB")};
+ JavacTask ct = (JavacTask)comp.getTask(null, null, null,
+ Arrays.asList("-d", classesDir.getPath()),
+ null, Arrays.asList(sources));
+ try {
+ if (!ct.call()) {
+ throw new AssertionError("Error thrown when compiling test cases");
+ }
+ } catch (Throwable ex) {
+ throw new AssertionError("Error thrown when compiling test cases");
+ }
+ check(classesDir,
+ "TestOneIgnorableChar.class",
+ "TestOneIgnorableChar$AABB.class",
+ "TestMultipleIgnorableChar.class",
+ "TestMultipleIgnorableChar$AABB.class");
+ if (errors > 0)
+ throw new AssertionError("There are some errors in the test check the error output");
+ }
+
+ /**
+ * Check that a directory contains the expected files.
+ */
+ void check(File dir, String... paths) {
+ Set<String> found = new TreeSet<String>(Arrays.asList(dir.list()));
+ Set<String> expect = new TreeSet<String>(Arrays.asList(paths));
+ if (found.equals(expect))
+ return;
+ for (String f: found) {
+ if (!expect.contains(f))
+ error("Unexpected file found: " + f);
+ }
+ for (String e: expect) {
+ if (!found.contains(e))
+ error("Expected file not found: " + e);
+ }
+ }
+
+ int errors;
+
+ void error(String msg) {
+ System.err.println(msg);
+ errors++;
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ String internalSource =
+ "public class #O {public class #I {} }";
+ public JavaSource(String outerClassName, String innerClassName) {
+ super(URI.create(outerClassName + ".java"), JavaFileObject.Kind.SOURCE);
+ internalSource =
+ internalSource.replace("#O", outerClassName).replace("#I", innerClassName);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return internalSource;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7153958
+ * @summary add constant pool reference to class containing inlined constants
+ * @compile pkg/ClassToBeStaticallyImported.java
+ * @run main CPoolRefClassContainingInlinedCts
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CPInfo;
+import com.sun.tools.classfile.ConstantPoolException;
+import java.io.File;
+import java.io.IOException;
+
+import static pkg.ClassToBeStaticallyImported.staticField;
+
+public class CPoolRefClassContainingInlinedCts {
+
+ public static void main(String args[]) throws Exception {
+ new CPoolRefClassContainingInlinedCts().run();
+ }
+
+ void run() throws Exception {
+ checkReferences();
+ }
+
+ int numberOfReferencedClassesToBeChecked = 0;
+
+ void checkClassName(String className) {
+ switch (className) {
+ case "SimpleAssignClass" : case "BinaryExpClass":
+ case "UnaryExpClass" : case "CastClass":
+ case "ParensClass" : case "CondClass":
+ case "IfClass" : case "pkg/ClassToBeStaticallyImported":
+ numberOfReferencedClassesToBeChecked++;
+ }
+ }
+
+ void checkReferences() throws IOException, ConstantPoolException {
+ File testClasses = new File(System.getProperty("test.classes"));
+ File file = new File(testClasses,
+ CPoolRefClassContainingInlinedCts.class.getName() + ".class");
+ ClassFile classFile = ClassFile.read(file);
+ int i = 1;
+ CPInfo cpInfo;
+ while (i < classFile.constant_pool.size()) {
+ cpInfo = classFile.constant_pool.get(i);
+ if (cpInfo instanceof CONSTANT_Class_info) {
+ checkClassName(((CONSTANT_Class_info)cpInfo).getName());
+ }
+ i += cpInfo.size();
+ }
+ if (numberOfReferencedClassesToBeChecked != 8) {
+ throw new AssertionError("Class reference missing in the constant pool");
+ }
+ }
+
+ private int assign = SimpleAssignClass.x;
+ private int binary = BinaryExpClass.x + 1;
+ private int unary = -UnaryExpClass.x;
+ private int cast = (int)CastClass.x;
+ private int parens = (ParensClass.x);
+ private int cond = (CondClass.x == 1) ? 1 : 2;
+ private static int ifConstant;
+ private static int importStatic;
+ static {
+ if (IfClass.x == 1) {
+ ifConstant = 1;
+ } else {
+ ifConstant = 2;
+ }
+ }
+ static {
+ if (staticField == 1) {
+ importStatic = 1;
+ } else {
+ importStatic = 2;
+ }
+ }
+}
+
+class SimpleAssignClass {
+ public static final int x = 1;
+}
+
+class BinaryExpClass {
+ public static final int x = 1;
+}
+
+class UnaryExpClass {
+ public static final int x = 1;
+}
+
+class CastClass {
+ public static final int x = 1;
+}
+
+class ParensClass {
+ public static final int x = 1;
+}
+
+class CondClass {
+ public static final int x = 1;
+}
+
+class IfClass {
+ public static final int x = 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package pkg;
+
+public class ClassToBeStaticallyImported {
+ public static final int staticField = 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeCastTest.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8002099
+ * @summary Add support for intersection types in cast expression
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class IntersectionTypeCastTest {
+
+ static int checkCount = 0;
+
+ interface Type {
+ boolean subtypeOf(Type that);
+ String asString();
+ boolean isClass();
+ boolean isInterface();
+ }
+
+ enum InterfaceKind implements Type {
+ A("interface A { }\n", "A", null),
+ B("interface B { }\n", "B", null),
+ C("interface C extends A { }\n", "C", A);
+
+ String declStr;
+ String typeStr;
+ InterfaceKind superInterface;
+
+ InterfaceKind(String declStr, String typeStr, InterfaceKind superInterface) {
+ this.declStr = declStr;
+ this.typeStr = typeStr;
+ this.superInterface = superInterface;
+ }
+
+ @Override
+ public boolean subtypeOf(Type that) {
+ return this == that || superInterface == that || that == ClassKind.OBJECT;
+ }
+
+ @Override
+ public String asString() {
+ return typeStr;
+ }
+
+ @Override
+ public boolean isClass() {
+ return false;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return true;
+ }
+ }
+
+ enum ClassKind implements Type {
+ OBJECT(null, "Object"),
+ CA("#M class CA implements A { }\n", "CA", InterfaceKind.A),
+ CB("#M class CB implements B { }\n", "CB", InterfaceKind.B),
+ CAB("#M class CAB implements A, B { }\n", "CAB", InterfaceKind.A, InterfaceKind.B),
+ CC("#M class CC implements C { }\n", "CC", InterfaceKind.C, InterfaceKind.A),
+ CCA("#M class CCA implements C, A { }\n", "CCA", InterfaceKind.C, InterfaceKind.A),
+ CCB("#M class CCB implements C, B { }\n", "CCB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B),
+ CCAB("#M class CCAB implements C, A, B { }\n", "CCAB", InterfaceKind.C, InterfaceKind.A, InterfaceKind.B);
+
+ String declTemplate;
+ String typeStr;
+ List<InterfaceKind> superInterfaces;
+
+ ClassKind(String declTemplate, String typeStr, InterfaceKind... superInterfaces) {
+ this.declTemplate = declTemplate;
+ this.typeStr = typeStr;
+ this.superInterfaces = List.from(superInterfaces);
+ }
+
+ String getDecl(ModifierKind mod) {
+ return declTemplate != null ?
+ declTemplate.replaceAll("#M", mod.modStr) :
+ "";
+ }
+
+ @Override
+ public boolean subtypeOf(Type that) {
+ return this == that || superInterfaces.contains(that) || that == OBJECT;
+ }
+
+ @Override
+ public String asString() {
+ return typeStr;
+ }
+
+ @Override
+ public boolean isClass() {
+ return true;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return false;
+ }
+ }
+
+ enum ModifierKind {
+ NONE(""),
+ FINAL("final");
+
+ String modStr;
+
+ ModifierKind(String modStr) {
+ this.modStr = modStr;
+ }
+ }
+
+ enum CastKind {
+ CLASS("(#C)", 0),
+ INTERFACE("(#I0)", 1),
+ INTERSECTION2("(#C & #I0)", 1),
+ INTERSECTION3("(#C & #I0 & #I1)", 2);
+ //INTERSECTION4("(#C & #I0 & #I1 & #I2)", 3);
+
+ String castTemplate;
+ int interfaceBounds;
+
+ CastKind(String castTemplate, int interfaceBounds) {
+ this.castTemplate = castTemplate;
+ this.interfaceBounds = interfaceBounds;
+ }
+ }
+
+ static class CastInfo {
+ CastKind kind;
+ Type[] types;
+
+ CastInfo(CastKind kind, Type... types) {
+ this.kind = kind;
+ this.types = types;
+ }
+
+ String getCast() {
+ String temp = kind.castTemplate.replaceAll("#C", types[0].asString());
+ for (int i = 0; i < kind.interfaceBounds ; i++) {
+ temp = temp.replace(String.format("#I%d", i), types[i + 1].asString());
+ }
+ return temp;
+ }
+
+ boolean hasDuplicateTypes() {
+ for (int i = 0 ; i < types.length ; i++) {
+ for (int j = 0 ; j < types.length ; j++) {
+ if (i != j && types[i] == types[j]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ boolean compatibleWith(ModifierKind mod, CastInfo that) {
+ for (Type t1 : types) {
+ for (Type t2 : that.types) {
+ boolean compat =
+ t1.subtypeOf(t2) ||
+ t2.subtypeOf(t1) ||
+ (t1.isInterface() && t2.isInterface()) || //side-cast (1)
+ (mod == ModifierKind.NONE && (t1.isInterface() != t2.isInterface())); //side-cast (2)
+ if (!compat) return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ //create default shared JavaCompiler - reused across multiple compilations
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ for (ModifierKind mod : ModifierKind.values()) {
+ for (CastInfo cast1 : allCastInfo()) {
+ for (CastInfo cast2 : allCastInfo()) {
+ new IntersectionTypeCastTest(mod, cast1, cast2).run(comp, fm);
+ }
+ }
+ }
+ System.out.println("Total check executed: " + checkCount);
+ }
+
+ static List<CastInfo> allCastInfo() {
+ ListBuffer<CastInfo> buf = ListBuffer.lb();
+ for (CastKind kind : CastKind.values()) {
+ for (ClassKind clazz : ClassKind.values()) {
+ if (kind == CastKind.INTERFACE && clazz != ClassKind.OBJECT) {
+ continue;
+ } else if (kind.interfaceBounds == 0) {
+ buf.append(new CastInfo(kind, clazz));
+ continue;
+ } else {
+ for (InterfaceKind intf1 : InterfaceKind.values()) {
+ if (kind.interfaceBounds == 1) {
+ buf.append(new CastInfo(kind, clazz, intf1));
+ continue;
+ } else {
+ for (InterfaceKind intf2 : InterfaceKind.values()) {
+ if (kind.interfaceBounds == 2) {
+ buf.append(new CastInfo(kind, clazz, intf1, intf2));
+ continue;
+ } else {
+ for (InterfaceKind intf3 : InterfaceKind.values()) {
+ buf.append(new CastInfo(kind, clazz, intf1, intf2, intf3));
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return buf.toList();
+ }
+
+ ModifierKind mod;
+ CastInfo cast1, cast2;
+ JavaSource source;
+ DiagnosticChecker diagChecker;
+
+ IntersectionTypeCastTest(ModifierKind mod, CastInfo cast1, CastInfo cast2) {
+ this.mod = mod;
+ this.cast1 = cast1;
+ this.cast2 = cast2;
+ this.source = new JavaSource();
+ this.diagChecker = new DiagnosticChecker();
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ String bodyTemplate = "class Test {\n" +
+ " void test() {\n" +
+ " Object o = #C1#C2null;\n" +
+ " } }";
+
+ String source = "";
+
+ public JavaSource() {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ for (ClassKind ck : ClassKind.values()) {
+ source += ck.getDecl(mod);
+ }
+ for (InterfaceKind ik : InterfaceKind.values()) {
+ source += ik.declStr;
+ }
+ source += bodyTemplate.replaceAll("#C1", cast1.getCast()).replaceAll("#C2", cast2.getCast());
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+ JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+ Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source));
+ try {
+ ct.analyze();
+ } catch (Throwable ex) {
+ throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
+ }
+ check();
+ }
+
+ void check() {
+ checkCount++;
+
+ boolean errorExpected = cast1.hasDuplicateTypes() || cast2.hasDuplicateTypes();
+
+ errorExpected |= !cast2.compatibleWith(mod, cast1);
+
+ if (errorExpected != diagChecker.errorFound) {
+ throw new Error("invalid diagnostics for source:\n" +
+ source.getCharContent(true) +
+ "\nFound error: " + diagChecker.errorFound +
+ "\nExpected error: " + errorExpected);
+ }
+ }
+
+ static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean errorFound;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/IntersectionTypeParserTest.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8002099
+ * @summary Add support for intersection types in cast expression
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class IntersectionTypeParserTest {
+
+ static int checkCount = 0;
+
+ enum TypeKind {
+ SIMPLE("A"),
+ GENERIC("A<X>"),
+ WILDCARD("A<? super X, ? extends Y>");
+
+ String typeStr;
+
+ TypeKind(String typeStr) {
+ this.typeStr = typeStr;
+ }
+ }
+
+ enum ArrayKind {
+ NONE(""),
+ SINGLE("[]"),
+ DOUBLE("[][]");
+
+ String arrStr;
+
+ ArrayKind(String arrStr) {
+ this.arrStr = arrStr;
+ }
+ }
+
+ static class Type {
+ TypeKind tk;
+ ArrayKind ak;
+
+ Type(TypeKind tk, ArrayKind ak) {
+ this.tk = tk;
+ this.ak = ak;
+ }
+
+ String asString() {
+ return tk.typeStr + ak.arrStr;
+ }
+ }
+
+ enum CastKind {
+ ONE("(#T0)", 1),
+ TWO("(#T0 & T1)", 2),
+ THREE("(#T0 & #T1 & #T2)", 3);
+
+ String castTemplate;
+ int nBounds;
+
+ CastKind(String castTemplate, int nBounds) {
+ this.castTemplate = castTemplate;
+ this.nBounds = nBounds;
+ }
+
+ String asString(Type... types) {
+ String res = castTemplate;
+ for (int i = 0; i < nBounds ; i++) {
+ res = res.replaceAll(String.format("#T%d", i), types[i].asString());
+ }
+ return res;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ //create default shared JavaCompiler - reused across multiple compilations
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ for (CastKind ck : CastKind.values()) {
+ for (TypeKind t1 : TypeKind.values()) {
+ for (ArrayKind ak1 : ArrayKind.values()) {
+ Type typ1 = new Type(t1, ak1);
+ if (ck.nBounds == 1) {
+ new IntersectionTypeParserTest(ck, typ1).run(comp, fm);
+ continue;
+ }
+ for (TypeKind t2 : TypeKind.values()) {
+ for (ArrayKind ak2 : ArrayKind.values()) {
+ Type typ2 = new Type(t2, ak2);
+ if (ck.nBounds == 2) {
+ new IntersectionTypeParserTest(ck, typ1, typ2).run(comp, fm);
+ continue;
+ }
+ for (TypeKind t3 : TypeKind.values()) {
+ for (ArrayKind ak3 : ArrayKind.values()) {
+ Type typ3 = new Type(t3, ak3);
+ new IntersectionTypeParserTest(ck, typ1, typ2, typ3).run(comp, fm);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ System.out.println("Total check executed: " + checkCount);
+ }
+
+ CastKind ck;
+ Type[] types;
+ JavaSource source;
+ DiagnosticChecker diagChecker;
+
+ IntersectionTypeParserTest(CastKind ck, Type... types) {
+ this.ck = ck;
+ this.types = types;
+ this.source = new JavaSource();
+ this.diagChecker = new DiagnosticChecker();
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ String bodyTemplate = "class Test {\n" +
+ " void test() {\n" +
+ " Object o = #Cnull;\n" +
+ " } }";
+
+ String source = "";
+
+ public JavaSource() {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ source += bodyTemplate.replaceAll("#C", ck.asString(types));
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+ checkCount++;
+ JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+ Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source));
+ ct.parse();
+ if (diagChecker.errorFound) {
+ throw new Error("Unexpected parser error for source:\n" +
+ source.getCharContent(true));
+ }
+ }
+
+ static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean errorFound;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/model/Check.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Annotation used by ModelChecker to mark the class whose model is to be checked
+ */
+@interface Check {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/model/IntersectionTypeInfo.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Used by ModelChecker to validate the modeling information of a union type.
+ */
+@interface IntersectionTypeInfo {
+ String[] value();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/model/Member.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.lang.model.element.ElementKind;
+
+/**
+ * Annotation used by ModelChecker to mark a member that is to be checked
+ */
+@interface Member {
+ ElementKind value();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/model/Model01.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8002099
+ * @summary Add support for intersection types in cast expression
+ * @library ../../../lib
+ * @build JavacTestingAbstractProcessor ModelChecker
+ * @compile -XDallowIntersectionTypes -processor ModelChecker Model01.java
+ */
+
+import javax.lang.model.element.ElementKind;
+
+@Check
+class Test {
+
+ interface A {
+ @Member(ElementKind.METHOD)
+ public void m1();
+ }
+
+ interface B {
+ @Member(ElementKind.METHOD)
+ public void m2();
+ }
+
+ void test(){
+ @IntersectionTypeInfo({"java.lang.Object", "Test.A", "Test.B"})
+ Object o = (A & B)null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/cast/intersection/model/ModelChecker.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.TypeCastTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.IntersectionType;
+import javax.lang.model.type.UnknownTypeException;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor7;
+
+@SupportedAnnotationTypes("Check")
+public class ModelChecker extends JavacTestingAbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver())
+ return true;
+
+ Trees trees = Trees.instance(processingEnv);
+
+ TypeElement testAnno = elements.getTypeElement("Check");
+ for (Element elem: roundEnv.getElementsAnnotatedWith(testAnno)) {
+ TreePath p = trees.getPath(elem);
+ new IntersectionCastTester(trees).scan(p, null);
+ }
+ return true;
+ }
+
+ class IntersectionCastTester extends TreePathScanner<Void, Void> {
+ Trees trees;
+
+ public IntersectionCastTester(Trees trees) {
+ super();
+ this.trees = trees;
+ }
+
+ @Override
+ public Void visitVariable(VariableTree node, Void p) {
+
+ TreePath varPath = new TreePath(getCurrentPath(), node);
+ Element v = trees.getElement(varPath);
+
+ IntersectionTypeInfo it = v.getAnnotation(IntersectionTypeInfo.class);
+ assertTrue(it != null, "IntersectionType annotation must be present");
+
+ ExpressionTree varInit = node.getInitializer();
+ assertTrue(varInit != null && varInit.getKind() == Tree.Kind.TYPE_CAST,
+ "variable must have be initialized to an expression containing an intersection type cast");
+
+ TypeMirror t = ((JCExpression)((TypeCastTree)varInit).getType()).type;
+
+ validateIntersectionTypeInfo(t, it);
+
+ for (Element e2 : types.asElement(t).getEnclosedElements()) {
+ assertTrue(false, "an intersection type has no declared members");
+ }
+
+ for (Element e2 : elements.getAllMembers((TypeElement)types.asElement(t))) {
+ Member m = e2.getAnnotation(Member.class);
+ if (m != null) {
+ assertTrue(e2.getKind() == m.value(), "Expected " + m.value() + " - found " + e2.getKind());
+ }
+ }
+
+ assertTrue(assertionCount == 10, "Expected 10 assertions - found " + assertionCount);
+ return super.visitVariable(node, p);
+ }
+ }
+
+ private void validateIntersectionTypeInfo(TypeMirror expectedIntersectionType, IntersectionTypeInfo it) {
+
+ assertTrue(expectedIntersectionType.getKind() == TypeKind.INTERSECTION, "INTERSECTION kind expected");
+
+ try {
+ new SimpleTypeVisitor6<Void, Void>(){}.visit(expectedIntersectionType);
+ throw new RuntimeException("Expected UnknownTypeException not thrown.");
+ } catch (UnknownTypeException ute) {
+ ; // Expected
+ }
+
+ try {
+ new SimpleTypeVisitor7<Void, Void>(){}.visit(expectedIntersectionType);
+ throw new RuntimeException("Expected UnknownTypeException not thrown.");
+ } catch (UnknownTypeException ute) {
+ ; // Expected
+ }
+
+ IntersectionType intersectionType = new SimpleTypeVisitor<IntersectionType, Void>(){
+ @Override
+ protected IntersectionType defaultAction(TypeMirror e, Void p) {return null;}
+
+ @Override
+ public IntersectionType visitIntersection(IntersectionType t, Void p) {return t;}
+ }.visit(expectedIntersectionType);
+ assertTrue(intersectionType != null, "Must get a non-null intersection type.");
+
+ assertTrue(it.value().length == intersectionType.getBounds().size(), "Cardinalities do not match");
+
+ String[] typeNames = it.value();
+ for(int i = 0; i < typeNames.length; i++) {
+ TypeMirror typeFromAnnotation = nameToType(typeNames[i]);
+ assertTrue(types.isSameType(typeFromAnnotation, intersectionType.getBounds().get(i)),
+ "Types were not equal.");
+ }
+ }
+
+ private TypeMirror nameToType(String name) {
+ return elements.getTypeElement(name).asType();
+ }
+
+ private static void assertTrue(boolean cond, String msg) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError(msg);
+ }
+
+ static int assertionCount = 0;
+}
--- a/langtools/test/tools/javac/defaultMethodExecution/DefaultMethodRegressionTests.java Thu Dec 06 12:04:44 2012 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 8003639
- * @summary convert lambda testng tests to jtreg and add them
- * @run testng DefaultMethodRegressionTests
- */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-/**
- * This set of classes/interfaces (K/I/C) is specially designed to expose a
- * bug in the JVM where it did not find some overloaded methods in some
- * specific situations. (fixed by hotspot changeset ffb9316fd9ed)
- */
-interface K {
- int bbb(Long l);
-}
-
-interface I extends K {
- default void aaa() {}
- default void aab() {}
- default void aac() {}
-
- default int bbb(Integer i) { return 22; }
- default int bbb(Float f) { return 33; }
- default int bbb(Long l) { return 44; }
- default int bbb(Double d) { return 55; }
- default int bbb(String s) { return 66; }
-
- default void caa() {}
- default void cab() {}
- default void cac() {}
-}
-
-class C implements I {}
-
-public class DefaultMethodRegressionTests {
-
- @Test(groups = "vm")
- public void testLostOverloadedMethod() {
- C c = new C();
- assertEquals(c.bbb(new Integer(1)), 22);
- assertEquals(c.bbb(new Float(1.1)), 33);
- assertEquals(c.bbb(new Long(1L)), 44);
- assertEquals(c.bbb(new Double(0.01)), 55);
- assertEquals(c.bbb(new String("")), 66);
- }
-
- // Test to ensure that the inference verifier accepts older classfiles
- // with classes that implement interfaces with defaults.
- @Test(groups = "vm")
- public void testInferenceVerifier() {
- // interface I { int m() default { return 99; } }
- byte I_bytes[] = {
- (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x33,
- 0x00, 0x08, 0x07, 0x00, 0x06, 0x07, 0x00, 0x07,
- 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x01, 0x00,
- 0x03, 0x28, 0x29, 0x49, 0x01, 0x00, 0x04, 0x43,
- 0x6f, 0x64, 0x65, 0x01, 0x00, 0x01, 0x49, 0x01,
- 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65,
- 0x63, 0x74, 0x06, 0x00, 0x00, 0x01, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01,
- 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x03, 0x10, 0x63, (byte)0xac, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00
- };
- // public class C implements I {} /* -target 1.5 */
- byte C_bytes[] = {
- (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x31,
- 0x00, 0x0c, 0x0a, 0x00, 0x03, 0x00, 0x08, 0x07,
- 0x00, 0x09, 0x07, 0x00, 0x0a, 0x07, 0x00, 0x0b,
- 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, 0x69, 0x74,
- 0x3e, 0x01, 0x00, 0x03, 0x28, 0x29, 0x56, 0x01,
- 0x00, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x0c, 0x00,
- 0x05, 0x00, 0x06, 0x01, 0x00, 0x01, 0x43, 0x01,
- 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65,
- 0x63, 0x74, 0x01, 0x00, 0x01, 0x49, 0x00, 0x21,
- 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05,
- 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x05, 0x2a, (byte)0xb7, 0x00, 0x01, (byte)0xb1, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- ClassLoader cl = new ClassLoader() {
- protected Class<?> findClass(String name) {
- if (name.equals("I")) {
- return defineClass("I", I_bytes, 0, I_bytes.length);
- } else if (name.equals("C")) {
- return defineClass("C", C_bytes, 0, C_bytes.length);
- } else {
- return null;
- }
- }
- };
- try {
- Class.forName("C", true, cl);
- } catch (Exception e) {
- // unmodified verifier will throw VerifyError
- fail("No exception should be thrown");
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @ignore 8004360
+ * @bug 8003639
+ * @summary convert lambda testng tests to jtreg and add them
+ * @run testng DefaultMethodRegressionTests
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * This set of classes/interfaces (K/I/C) is specially designed to expose a
+ * bug in the JVM where it did not find some overloaded methods in some
+ * specific situations. (fixed by hotspot changeset ffb9316fd9ed)
+ */
+interface K {
+ int bbb(Long l);
+}
+
+interface I extends K {
+ default void aaa() {}
+ default void aab() {}
+ default void aac() {}
+
+ default int bbb(Integer i) { return 22; }
+ default int bbb(Float f) { return 33; }
+ default int bbb(Long l) { return 44; }
+ default int bbb(Double d) { return 55; }
+ default int bbb(String s) { return 66; }
+
+ default void caa() {}
+ default void cab() {}
+ default void cac() {}
+}
+
+class C implements I {}
+
+public class DefaultMethodRegressionTests {
+
+ @Test(groups = "vm")
+ public void testLostOverloadedMethod() {
+ C c = new C();
+ assertEquals(c.bbb(new Integer(1)), 22);
+ assertEquals(c.bbb(new Float(1.1)), 33);
+ assertEquals(c.bbb(new Long(1L)), 44);
+ assertEquals(c.bbb(new Double(0.01)), 55);
+ assertEquals(c.bbb(new String("")), 66);
+ }
+
+ // Test to ensure that the inference verifier accepts older classfiles
+ // with classes that implement interfaces with defaults.
+ @Test(groups = "vm")
+ public void testInferenceVerifier() {
+ // interface I { int m() default { return 99; } }
+ byte I_bytes[] = {
+ (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x33,
+ 0x00, 0x08, 0x07, 0x00, 0x06, 0x07, 0x00, 0x07,
+ 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x01, 0x00,
+ 0x03, 0x28, 0x29, 0x49, 0x01, 0x00, 0x04, 0x43,
+ 0x6f, 0x64, 0x65, 0x01, 0x00, 0x01, 0x49, 0x01,
+ 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65,
+ 0x63, 0x74, 0x06, 0x00, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01,
+ 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x03, 0x10, 0x63, (byte)0xac, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ // public class C implements I {} /* -target 1.5 */
+ byte C_bytes[] = {
+ (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x31,
+ 0x00, 0x0c, 0x0a, 0x00, 0x03, 0x00, 0x08, 0x07,
+ 0x00, 0x09, 0x07, 0x00, 0x0a, 0x07, 0x00, 0x0b,
+ 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, 0x69, 0x74,
+ 0x3e, 0x01, 0x00, 0x03, 0x28, 0x29, 0x56, 0x01,
+ 0x00, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x0c, 0x00,
+ 0x05, 0x00, 0x06, 0x01, 0x00, 0x01, 0x43, 0x01,
+ 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c,
+ 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65,
+ 0x63, 0x74, 0x01, 0x00, 0x01, 0x49, 0x00, 0x21,
+ 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05,
+ 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x05, 0x2a, (byte)0xb7, 0x00, 0x01, (byte)0xb1, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ ClassLoader cl = new ClassLoader() {
+ protected Class<?> findClass(String name) {
+ if (name.equals("I")) {
+ return defineClass("I", I_bytes, 0, I_bytes.length);
+ } else if (name.equals("C")) {
+ return defineClass("C", C_bytes, 0, C_bytes.length);
+ } else {
+ return null;
+ }
+ }
+ };
+ try {
+ Class.forName("C", true, cl);
+ } catch (Exception e) {
+ // unmodified verifier will throw VerifyError
+ fail("No exception should be thrown");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/IntersectionTypesInCastNotSupported.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.intersection.types.in.cast.not.supported.in.source
+// options: -source 7 -Xlint:-options
+
+interface IntersectionTypesInCastNotSupported {
+ Object o = (A & B)null;
+}
--- a/langtools/test/tools/javac/diags/examples/InvalidGenericDescInFunctionalInterface.java Thu Dec 06 12:04:44 2012 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.err.prob.found.req
-// key: compiler.misc.invalid.generic.desc.in.functional.intf
-
-class InvalidGenericDescInFunctionalIntf {
-
- interface SAM {
- <Z> void m();
- }
-
- SAM s = x-> { };
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/InvalidGenericLambdaTarget.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.invalid.generic.lambda.target
+
+class InvalidGenericLambdaTarget {
+
+ interface SAM {
+ <Z> void m();
+ }
+
+ SAM s = x-> { };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/SecondaryBoundMustBeMarkerIntf.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.secondary.bound.must.be.marker.intf
+// options: -XDallowIntersectionTypes
+
+class SecondaryBoundMustBeMarkerInterface {
+ Runnable r = (Runnable & Comparable<?>)()->{};
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/StaticBoundMref.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.invalid.mref
+// key: compiler.misc.static.bound.mref
+
+class StaticBoundMref {
+
+ Runnable r = new StaticBoundMref()::m;
+
+ static void m() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/StaticMrefWithTargs.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.invalid.mref
+// key: compiler.misc.static.mref.with.targs
+
+class StaticMrefWithTargs<X> {
+
+ Runnable r = StaticMrefWithTargs<String>::m;
+
+ static void m() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8003280 8004102
+ * @summary Add lambda tests
+ * perform several automated checks in lambda conversion, esp. around accessibility
+ * @author Maurizio Cimadamore
+ * @run main FunctionalInterfaceConversionTest
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class FunctionalInterfaceConversionTest {
+
+ enum PackageKind {
+ NO_PKG(""),
+ PKG_A("a");
+
+ String pkg;
+
+ PackageKind(String pkg) {
+ this.pkg = pkg;
+ }
+
+ String getPkgDecl() {
+ return this == NO_PKG ?
+ "" :
+ "package " + pkg + ";";
+ }
+
+ String getImportStat() {
+ return this == NO_PKG ?
+ "" :
+ "import " + pkg + ".*;";
+ }
+ }
+
+ enum SamKind {
+ CLASS("public class Sam { }"),
+ ABSTACT_CLASS("public abstract class Sam { }"),
+ ANNOTATION("public @interface Sam { }"),
+ ENUM("public enum Sam { }"),
+ INTERFACE("public interface Sam { \n #METH; \n }");
+
+ String sam_str;
+
+ SamKind(String sam_str) {
+ this.sam_str = sam_str;
+ }
+
+ String getSam(String methStr) {
+ return sam_str.replaceAll("#METH", methStr);
+ }
+ }
+
+ enum ModifierKind {
+ PUBLIC("public"),
+ PACKAGE("");
+
+ String modifier_str;
+
+ ModifierKind(String modifier_str) {
+ this.modifier_str = modifier_str;
+ }
+
+ boolean stricterThan(ModifierKind that) {
+ return this.ordinal() > that.ordinal();
+ }
+ }
+
+ enum TypeKind {
+ EXCEPTION("Exception"),
+ PKG_CLASS("PackageClass");
+
+ String typeStr;
+
+ private TypeKind(String typeStr) {
+ this.typeStr = typeStr;
+ }
+ }
+
+ enum ExprKind {
+ LAMBDA("x -> null"),
+ MREF("this::m");
+
+ String exprStr;
+
+ private ExprKind(String exprStr) {
+ this.exprStr = exprStr;
+ }
+ }
+
+ enum MethodKind {
+ NONE(""),
+ NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
+ GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
+
+ String methodTemplate;
+
+ private MethodKind(String methodTemplate) {
+ this.methodTemplate = methodTemplate;
+ }
+
+ String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
+ return methodTemplate.replaceAll("#R", retType.typeStr).
+ replaceAll("#ARG", argType.typeStr).
+ replaceAll("#T", thrownType.typeStr);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+ for (PackageKind samPkg : PackageKind.values()) {
+ for (ModifierKind modKind : ModifierKind.values()) {
+ for (SamKind samKind : SamKind.values()) {
+ for (MethodKind samMeth : MethodKind.values()) {
+ for (MethodKind clientMeth : MethodKind.values()) {
+ for (TypeKind retType : TypeKind.values()) {
+ for (TypeKind argType : TypeKind.values()) {
+ for (TypeKind thrownType : TypeKind.values()) {
+ for (ExprKind exprKind : ExprKind.values()) {
+ new FunctionalInterfaceConversionTest(samPkg, modKind, samKind,
+ samMeth, clientMeth, retType, argType, thrownType, exprKind).test(comp, fm);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ PackageKind samPkg;
+ ModifierKind modKind;
+ SamKind samKind;
+ MethodKind samMeth;
+ MethodKind clientMeth;
+ TypeKind retType;
+ TypeKind argType;
+ TypeKind thrownType;
+ ExprKind exprKind;
+ DiagnosticChecker dc;
+
+ SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
+ public String toString() {
+ return template.replaceAll("#P", samPkg.getPkgDecl()).
+ replaceAll("#C", samKind.getSam(samMeth.getMethod(retType, argType, thrownType)));
+ }
+ };
+
+ SourceFile pkgClassSourceFile = new SourceFile("PackageClass.java",
+ "#P\n #M class PackageClass extends Exception { }") {
+ public String toString() {
+ return template.replaceAll("#P", samPkg.getPkgDecl()).
+ replaceAll("#M", modKind.modifier_str);
+ }
+ };
+
+ SourceFile clientSourceFile = new SourceFile("Client.java",
+ "#I\n abstract class Client { \n" +
+ " Sam s = #E;\n" +
+ " #M \n }") {
+ public String toString() {
+ return template.replaceAll("#I", samPkg.getImportStat())
+ .replaceAll("#E", exprKind.exprStr)
+ .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
+ }
+ };
+
+ FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
+ MethodKind samMeth, MethodKind clientMeth, TypeKind retType, TypeKind argType,
+ TypeKind thrownType, ExprKind exprKind) {
+ this.samPkg = samPkg;
+ this.modKind = modKind;
+ this.samKind = samKind;
+ this.samMeth = samMeth;
+ this.clientMeth = clientMeth;
+ this.retType = retType;
+ this.argType = argType;
+ this.thrownType = thrownType;
+ this.exprKind = exprKind;
+ this.dc = new DiagnosticChecker();
+ }
+
+ void test(JavaCompiler comp, StandardJavaFileManager fm) throws Exception {
+ JavacTask ct = (JavacTask)comp.getTask(null, fm, dc,
+ null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
+ ct.analyze();
+ if (dc.errorFound == checkSamConversion()) {
+ throw new AssertionError(samSourceFile + "\n\n" + pkgClassSourceFile + "\n\n" + clientSourceFile);
+ }
+ }
+
+ boolean checkSamConversion() {
+ if (samKind != SamKind.INTERFACE) {
+ //sam type must be an interface
+ return false;
+ } else if (samMeth == MethodKind.NONE) {
+ //interface must have at least a method
+ return false;
+ } else if (exprKind == ExprKind.LAMBDA &&
+ samMeth != MethodKind.NON_GENERIC) {
+ //target method for lambda must be non-generic
+ return false;
+ } else if (exprKind == ExprKind.MREF &&
+ clientMeth == MethodKind.NONE) {
+ return false;
+ } else if (samPkg != PackageKind.NO_PKG &&
+ modKind != ModifierKind.PUBLIC &&
+ (retType == TypeKind.PKG_CLASS ||
+ argType == TypeKind.PKG_CLASS ||
+ thrownType == TypeKind.PKG_CLASS)) {
+ //target must not contain inaccessible types
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ abstract class SourceFile extends SimpleJavaFileObject {
+
+ protected String template;
+
+ public SourceFile(String filename, String template) {
+ super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
+ this.template = template;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return toString();
+ }
+
+ public abstract String toString();
+ }
+
+ static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean errorFound = false;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/Intersection01.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8002099
+ * @summary Add support for intersection types in cast expression
+ * @compile/fail/ref=Intersection01.out -XDallowIntersectionTypes -XDrawDiagnostics Intersection01.java
+ */
+class Intersection01 {
+
+ interface SAM {
+ void m();
+ }
+
+ Object o1 = (java.io.Serializable & SAM)()->{};
+ Object o2 = (SAM & java.io.Serializable)()->{};
+ Object o3 = (java.io.Serializable & SAM)Intersection01::m;
+ Object o4 = (SAM & java.io.Serializable)Intersection01::m;
+
+ static void m() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/Intersection01.out Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,3 @@
+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))
+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))
+2 errors
--- a/langtools/test/tools/javac/lambda/LambdaConv21.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.java Mon Dec 10 20:59:38 2012 -0800
@@ -23,7 +23,7 @@
static void testExpressionLambda() {
SAM_void s1 = ()->m_void(); //ok
SAM_java_lang_Void s2 = ()->m_void(); //no - incompatible target
- SAM_void s3 = ()->m_java_lang_Void(); //no - incompatible target
+ SAM_void s3 = ()->m_java_lang_Void(); //ok - expression statement lambda is compatible with void
SAM_java_lang_Void s4 = ()->m_java_lang_Void(); //ok
}
--- a/langtools/test/tools/javac/lambda/LambdaConv21.out Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv21.out Mon Dec 10 20:59:38 2012 -0800
@@ -1,6 +1,5 @@
LambdaConv21.java:25:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: void, java.lang.Void))
-LambdaConv21.java:26:43: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Void, void))
LambdaConv21.java:32:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
LambdaConv21.java:33:53: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val))
LambdaConv21.java:36:33: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.Void))
-5 errors
+4 errors
--- a/langtools/test/tools/javac/lambda/LambdaConversionTest.java Thu Dec 06 12:04:44 2012 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 8003280
- * @summary Add lambda tests
- * perform several automated checks in lambda conversion, esp. around accessibility
- * @author Maurizio Cimadamore
- * @run main LambdaConversionTest
- */
-
-import com.sun.source.util.JavacTask;
-import java.net.URI;
-import java.util.Arrays;
-import javax.tools.Diagnostic;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
-
-public class LambdaConversionTest {
-
- enum PackageKind {
- NO_PKG(""),
- PKG_A("a");
-
- String pkg;
-
- PackageKind(String pkg) {
- this.pkg = pkg;
- }
-
- String getPkgDecl() {
- return this == NO_PKG ?
- "" :
- "package " + pkg + ";";
- }
-
- String getImportStat() {
- return this == NO_PKG ?
- "" :
- "import " + pkg + ".*;";
- }
- }
-
- enum SamKind {
- CLASS("public class Sam { }"),
- ABSTACT_CLASS("public abstract class Sam { }"),
- ANNOTATION("public @interface Sam { }"),
- ENUM("public enum Sam { }"),
- INTERFACE("public interface Sam { \n #METH; \n }");
-
- String sam_str;
-
- SamKind(String sam_str) {
- this.sam_str = sam_str;
- }
-
- String getSam(String methStr) {
- return sam_str.replaceAll("#METH", methStr);
- }
- }
-
- enum ModifierKind {
- PUBLIC("public"),
- PACKAGE("");
-
- String modifier_str;
-
- ModifierKind(String modifier_str) {
- this.modifier_str = modifier_str;
- }
-
- boolean stricterThan(ModifierKind that) {
- return this.ordinal() > that.ordinal();
- }
- }
-
- enum TypeKind {
- EXCEPTION("Exception"),
- PKG_CLASS("PackageClass");
-
- String typeStr;
-
- private TypeKind(String typeStr) {
- this.typeStr = typeStr;
- }
- }
-
- enum MethodKind {
- NONE(""),
- NON_GENERIC("public #R m(#ARG s) throws #T;"),
- GENERIC("public <X> #R m(#ARG s) throws #T;");
-
- String methodTemplate;
-
- private MethodKind(String methodTemplate) {
- this.methodTemplate = methodTemplate;
- }
-
- String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
- return methodTemplate.replaceAll("#R", retType.typeStr).
- replaceAll("#ARG", argType.typeStr).
- replaceAll("#T", thrownType.typeStr);
- }
- }
-
- public static void main(String[] args) throws Exception {
- for (PackageKind samPkg : PackageKind.values()) {
- for (ModifierKind modKind : ModifierKind.values()) {
- for (SamKind samKind : SamKind.values()) {
- for (MethodKind meth : MethodKind.values()) {
- for (TypeKind retType : TypeKind.values()) {
- for (TypeKind argType : TypeKind.values()) {
- for (TypeKind thrownType : TypeKind.values()) {
- new LambdaConversionTest(samPkg, modKind, samKind,
- meth, retType, argType, thrownType).test();
- }
- }
- }
- }
- }
- }
- }
- }
-
- PackageKind samPkg;
- ModifierKind modKind;
- SamKind samKind;
- MethodKind meth;
- TypeKind retType;
- TypeKind argType;
- TypeKind thrownType;
-
- SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
- public String toString() {
- return template.replaceAll("#P", samPkg.getPkgDecl()).
- replaceAll("#C", samKind.getSam(meth.getMethod(retType, argType, thrownType)));
- }
- };
-
- SourceFile pkgClassSourceFile = new SourceFile("PackageClass.java",
- "#P\n #M class PackageClass extends Exception { }") {
- public String toString() {
- return template.replaceAll("#P", samPkg.getPkgDecl()).
- replaceAll("#M", modKind.modifier_str);
- }
- };
-
- SourceFile clientSourceFile = new SourceFile("Client.java",
- "#I\n class Client { Sam s = x -> null; }") {
- public String toString() {
- return template.replaceAll("#I", samPkg.getImportStat());
- }
- };
-
- LambdaConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
- MethodKind meth, TypeKind retType, TypeKind argType, TypeKind thrownType) {
- this.samPkg = samPkg;
- this.modKind = modKind;
- this.samKind = samKind;
- this.meth = meth;
- this.retType = retType;
- this.argType = argType;
- this.thrownType = thrownType;
- }
-
- void test() throws Exception {
- final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
- DiagnosticChecker dc = new DiagnosticChecker();
- JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
- null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
- ct.analyze();
- if (dc.errorFound == checkSamConversion()) {
- throw new AssertionError(samSourceFile + "\n\n" + pkgClassSourceFile + "\n\n" + clientSourceFile);
- }
- }
-
- boolean checkSamConversion() {
- if (samKind != SamKind.INTERFACE) {
- //sam type must be an interface
- return false;
- } else if (meth != MethodKind.NON_GENERIC) {
- //target method must be non-generic
- return false;
- } else if (samPkg != PackageKind.NO_PKG &&
- modKind != ModifierKind.PUBLIC &&
- (retType == TypeKind.PKG_CLASS ||
- argType == TypeKind.PKG_CLASS ||
- thrownType == TypeKind.PKG_CLASS)) {
- //target must not contain inaccessible types
- return false;
- } else {
- return true;
- }
- }
-
- abstract class SourceFile extends SimpleJavaFileObject {
-
- protected String template;
-
- public SourceFile(String filename, String template) {
- super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
- this.template = template;
- }
-
- @Override
- public CharSequence getCharContent(boolean ignoreEncodingErrors) {
- return toString();
- }
-
- public abstract String toString();
- }
-
- static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
-
- boolean errorFound = false;
-
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
- errorFound = true;
- }
- }
- }
-}
--- a/langtools/test/tools/javac/lambda/LambdaParserTest.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaParserTest.java Mon Dec 10 20:59:38 2012 -0800
@@ -90,9 +90,14 @@
enum LambdaParameterKind {
IMPLICIT(""),
EXPLIICT_SIMPLE("A"),
+ EXPLIICT_SIMPLE_ARR1("A[]"),
+ EXPLIICT_SIMPLE_ARR2("A[][]"),
EXPLICIT_VARARGS("A..."),
EXPLICIT_GENERIC1("A<X>"),
- EXPLICIT_GENERIC3("A<? extends X, ? super Y>");
+ EXPLICIT_GENERIC2("A<? extends X, ? super Y>"),
+ EXPLICIT_GENERIC2_VARARGS("A<? extends X, ? super Y>..."),
+ EXPLICIT_GENERIC2_ARR1("A<? extends X, ? super Y>[]"),
+ EXPLICIT_GENERIC2_ARR2("A<? extends X, ? super Y>[][]");
String parameterType;
@@ -103,6 +108,11 @@
boolean explicit() {
return this != IMPLICIT;
}
+
+ boolean isVarargs() {
+ return this == EXPLICIT_VARARGS ||
+ this == EXPLICIT_GENERIC2_VARARGS;
+ }
}
enum ModifierKind {
@@ -253,7 +263,7 @@
if (lk.arity() == 2 &&
(pk1.explicit() != pk2.explicit() ||
- pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) {
+ pk1.isVarargs())) {
errorExpected = true;
}
--- a/langtools/test/tools/javac/lambda/MethodReference30.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/MethodReference30.java Mon Dec 10 20:59:38 2012 -0800
@@ -46,7 +46,7 @@
assertTrue(true);
}
- static void m() { }
+ void m() { }
public static void main(String[] args) {
SAM s = new MethodReference30()::m;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference55.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004101
+ * @summary Add checks for method reference well-formedness
+ * @compile/fail/ref=MethodReference55.out -XDrawDiagnostics MethodReference55.java
+ */
+class MethodReference55<X> {
+
+ interface V {
+ void m(Object o);
+ }
+
+ V v = new MethodReference55<String>()::m;
+
+ void test() {
+ g(new MethodReference55<String>()::m);
+ }
+
+ void g(V v) { }
+
+ static void m(Object o) { };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference55.out Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,3 @@
+MethodReference55.java:36:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
+MethodReference55.java:39:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference56.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004101
+ * @summary Add checks for method reference well-formedness
+ * @compile/fail/ref=MethodReference56.out -XDrawDiagnostics MethodReference56.java
+ */
+class MethodReference56<X> {
+
+ interface V {
+ void m(Object o);
+ }
+
+ V v = MethodReference56<String>::m;
+
+ void test() {
+ g(MethodReference56<String>::m);
+ }
+
+ void g(V v) { }
+
+ static void m(Object o) { };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference56.out Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,3 @@
+MethodReference56.java:36:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
+MethodReference56.java:39:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference57.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004102
+ * @summary Add support for generic functional descriptors
+ * @compile MethodReference57.java
+ */
+class MethodReference57 {
+
+ interface F {
+ <X> void m();
+ }
+
+ void test() {
+ F f = this::g; //ok
+ }
+
+ void g() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference58.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004102
+ * @summary Add support for generic functional descriptors
+ * @compile/fail/ref=MethodReference58.out -XDrawDiagnostics MethodReference58.java
+ */
+class MethodReference58 {
+
+ interface F_Object {
+ <X> void m(X x);
+ }
+
+ interface F_Integer {
+ <X extends Integer> void m(X x);
+ }
+
+ void test() {
+ F_Object f1 = this::g; //incompatible bounds
+ F_Integer f2 = this::g; //ok
+ }
+
+ <Z extends Number> void g(Z z) { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference58.out Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,2 @@
+MethodReference58.java:41:23: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, Z, X, kindname.class, MethodReference58, (compiler.misc.inferred.do.not.conform.to.upper.bounds: X, java.lang.Number)))
+1 error
--- a/langtools/test/tools/javac/lambda/VoidCompatibility.out Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/VoidCompatibility.out Mon Dec 10 20:59:38 2012 -0800
@@ -1,2 +1,3 @@
+VoidCompatibility.java:17:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility
VoidCompatibility.java:23:9: compiler.err.ref.ambiguous: schedule, kindname.method, schedule(VoidCompatibility.Runnable), VoidCompatibility, kindname.method, schedule(VoidCompatibility.Thunk<?>), VoidCompatibility
-1 error
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8002099
+ * @summary Add support for intersection types in cast expression
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class IntersectionTargetTypeTest {
+
+ static int checkCount = 0;
+
+ enum BoundKind {
+ INTF,
+ CLASS,
+ SAM,
+ ZAM;
+ }
+
+ enum MethodKind {
+ NONE,
+ ABSTRACT,
+ DEFAULT;
+ }
+
+ enum TypeKind {
+ A("interface A { }\n", "A", BoundKind.ZAM),
+ B("interface B { default void m() { } }\n", "B", BoundKind.ZAM),
+ C("interface C { void m(); }\n", "C", BoundKind.SAM),
+ D("interface D extends B { }\n", "D", BoundKind.ZAM),
+ E("interface E extends C { }\n", "E", BoundKind.SAM),
+ F("interface F extends C { void g(); }\n", "F", BoundKind.INTF),
+ G("interface G extends B { void g(); }\n", "G", BoundKind.SAM),
+ H("interface H extends A { void g(); }\n", "H", BoundKind.SAM),
+ OBJECT("", "Object", BoundKind.CLASS),
+ STRING("", "String", BoundKind.CLASS);
+
+ String declStr;
+ String typeStr;
+ BoundKind boundKind;
+
+ private TypeKind(String declStr, String typeStr, BoundKind boundKind) {
+ this.declStr = declStr;
+ this.typeStr = typeStr;
+ this.boundKind = boundKind;
+ }
+
+ boolean compatibleSupertype(TypeKind tk) {
+ if (tk == this) return true;
+ switch (tk) {
+ case B:
+ return this != C && this != E && this != F;
+ case C:
+ return this != B && this != C && this != D && this != G;
+ case D: return compatibleSupertype(B);
+ case E:
+ case F: return compatibleSupertype(C);
+ case G: return compatibleSupertype(B);
+ case H: return compatibleSupertype(A);
+ default:
+ return true;
+ }
+ }
+ }
+
+ enum CastKind {
+ ONE_ARY("(#B0)", 1),
+ TWO_ARY("(#B0 & #B1)", 2),
+ THREE_ARY("(#B0 & #B1 & #B2)", 3);
+
+ String castTemplate;
+ int nbounds;
+
+ CastKind(String castTemplate, int nbounds) {
+ this.castTemplate = castTemplate;
+ this.nbounds = nbounds;
+ }
+ }
+
+ enum ExpressionKind {
+ LAMBDA("()->{}", true),
+ MREF("this::m", true),
+ //COND_LAMBDA("(true ? ()->{} : ()->{})", true), re-enable if spec allows this
+ //COND_MREF("(true ? this::m : this::m)", true),
+ STANDALONE("null", false);
+
+ String exprString;
+ boolean isFunctional;
+
+ private ExpressionKind(String exprString, boolean isFunctional) {
+ this.exprString = exprString;
+ this.isFunctional = isFunctional;
+ }
+ }
+
+ static class CastInfo {
+ CastKind kind;
+ TypeKind[] types;
+
+ CastInfo(CastKind kind, TypeKind... types) {
+ this.kind = kind;
+ this.types = types;
+ }
+
+ String getCast() {
+ String temp = kind.castTemplate;
+ for (int i = 0; i < kind.nbounds ; i++) {
+ temp = temp.replace(String.format("#B%d", i), types[i].typeStr);
+ }
+ return temp;
+ }
+
+ boolean wellFormed() {
+ //check for duplicate types
+ for (int i = 0 ; i < types.length ; i++) {
+ for (int j = 0 ; j < types.length ; j++) {
+ if (i != j && types[i] == types[j]) {
+ return false;
+ }
+ }
+ }
+ //check that classes only appear as first bound
+ boolean classOk = true;
+ for (int i = 0 ; i < types.length ; i++) {
+ if (types[i].boundKind == BoundKind.CLASS &&
+ !classOk) {
+ return false;
+ }
+ classOk = false;
+ }
+ //check that supertypes are mutually compatible
+ for (int i = 0 ; i < types.length ; i++) {
+ for (int j = 0 ; j < types.length ; j++) {
+ if (!types[i].compatibleSupertype(types[j]) && i != j) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ public static void main(String... args) throws Exception {
+ //create default shared JavaCompiler - reused across multiple compilations
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ for (CastInfo cInfo : allCastInfo()) {
+ for (ExpressionKind ek : ExpressionKind.values()) {
+ new IntersectionTargetTypeTest(cInfo, ek).run(comp, fm);
+ }
+ }
+ System.out.println("Total check executed: " + checkCount);
+ }
+
+ static List<CastInfo> allCastInfo() {
+ ListBuffer<CastInfo> buf = ListBuffer.lb();
+ for (CastKind kind : CastKind.values()) {
+ for (TypeKind b1 : TypeKind.values()) {
+ if (kind.nbounds == 1) {
+ buf.append(new CastInfo(kind, b1));
+ continue;
+ } else {
+ for (TypeKind b2 : TypeKind.values()) {
+ if (kind.nbounds == 2) {
+ buf.append(new CastInfo(kind, b1, b2));
+ continue;
+ } else {
+ for (TypeKind b3 : TypeKind.values()) {
+ buf.append(new CastInfo(kind, b1, b2, b3));
+ }
+ }
+ }
+ }
+ }
+ }
+ return buf.toList();
+ }
+
+ CastInfo cInfo;
+ ExpressionKind ek;
+ JavaSource source;
+ DiagnosticChecker diagChecker;
+
+ IntersectionTargetTypeTest(CastInfo cInfo, ExpressionKind ek) {
+ this.cInfo = cInfo;
+ this.ek = ek;
+ this.source = new JavaSource();
+ this.diagChecker = new DiagnosticChecker();
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ String bodyTemplate = "class Test {\n" +
+ " void m() { }\n" +
+ " void test() {\n" +
+ " Object o = #C#E;\n" +
+ " } }";
+
+ String source = "";
+
+ public JavaSource() {
+ super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+ for (TypeKind tk : TypeKind.values()) {
+ source += tk.declStr;
+ }
+ source += bodyTemplate.replaceAll("#C", cInfo.getCast()).replaceAll("#E", ek.exprString);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+
+ void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+ JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+ Arrays.asList("-XDallowIntersectionTypes"), null, Arrays.asList(source));
+ try {
+ ct.analyze();
+ } catch (Throwable ex) {
+ throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true));
+ }
+ check();
+ }
+
+ void check() {
+ checkCount++;
+
+ boolean errorExpected = !cInfo.wellFormed();
+
+ if (ek.isFunctional) {
+ //first bound must be a SAM
+ errorExpected |= cInfo.types[0].boundKind != BoundKind.SAM;
+ if (cInfo.types.length > 1) {
+ //additional bounds must be ZAMs
+ for (int i = 1; i < cInfo.types.length; i++) {
+ errorExpected |= cInfo.types[i].boundKind != BoundKind.ZAM;
+ }
+ }
+ }
+
+ if (errorExpected != diagChecker.errorFound) {
+ throw new Error("invalid diagnostics for source:\n" +
+ source.getCharContent(true) +
+ "\nFound error: " + diagChecker.errorFound +
+ "\nExpected error: " + errorExpected);
+ }
+ }
+
+ static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ boolean errorFound;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- a/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/methodReference/MethodRef1.java Mon Dec 10 20:59:38 2012 -0800
@@ -70,9 +70,6 @@
b = MethodRef1::foo; //static reference to foo(int)
b.m(1);
- b = new MethodRef1()::foo; //instance reference to static methods, supported for now
- b.m(1);
-
b = MethodRef1::bar; //static reference to bar(int)
b.m(2);
--- a/langtools/test/tools/javac/lambda/methodReference/SamConversion.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/methodReference/SamConversion.java Mon Dec 10 20:59:38 2012 -0800
@@ -133,15 +133,6 @@
} catch (Exception e) {
assertTrue(false);
}
-
- bar = new A()::method6;
- try {
- bar.m(1);
- assertTrue(false);
- } catch (MyException e) {
- } catch (Exception e) {
- assertTrue(false);
- }
}
/**
--- a/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java Thu Dec 06 12:04:44 2012 -0800
+++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestKinds.java Mon Dec 10 20:59:38 2012 -0800
@@ -119,20 +119,6 @@
assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
}
- public void testMRStaticEval() {
- MethodReferenceTestKinds evalCheck;
- S0 var = (evalCheck = inst("discard"))::staticMethod0;
- assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
- assertEquals(var.get(), "SM:0");
- }
-
- public void testMRStaticEvalArg() {
- MethodReferenceTestKinds evalCheck;
- S1 var = (evalCheck = inst("discard"))::staticMethod1;
- assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
- assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
- }
-
public void testMRTopLevel() {
SN0 var = MethodReferenceTestKindsBase::new;
assertEquals(var.make().toString(), "MethodReferenceTestKindsBase(blank)");
@@ -142,17 +128,7 @@
SN1 var = MethodReferenceTestKindsBase::new;
assertEquals(var.make("name").toString(), "MethodReferenceTestKindsBase(name)");
}
-/* unbound inner case not supported anymore (dropped by EG)
- public void testMRUnboundInner() {
- SXN0 var = MethodReferenceTestKinds.In::new;
- assertEquals(var.make(inst("out")).toString(), "In(blank)");
- }
- public void testMRUnboundInnerArg() {
- SXN1 var = MethodReferenceTestKinds.In::new;
- assertEquals(var.make(inst("out"), "name").toString(), "In(name)");
- }
-*/
public void testMRImplicitInner() {
SN0 var = MethodReferenceTestKinds.In::new;
assertEquals(var.make().toString(), "In(blank)");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/T7190862.java Mon Dec 10 20:59:38 2012 -0800
@@ -0,0 +1,157 @@
+
+/*
+ * @test /nodynamiccopyright/
+ * @bug 7190862 7109747
+ * @summary javap shows an incorrect type for operands if the 'wide' prefix is used
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javap.JavapFileManager;
+import com.sun.tools.javap.JavapTask;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class T7190862 {
+
+ enum TypeWideInstructionMap {
+ INT("int", new String[]{"istore_w", "iload_w"}),
+ LONG("long", new String[]{"lstore_w", "lload_w"}),
+ FLOAT("float", new String[]{"fstore_w", "fload_w"}),
+ DOUBLE("double", new String[]{"dstore_w", "dload_w"}),
+ OBJECT("Object", new String[]{"astore_w", "aload_w"});
+
+ String type;
+ String[] instructions;
+
+ TypeWideInstructionMap(String type, String[] instructions) {
+ this.type = type;
+ this.instructions = instructions;
+ }
+ }
+
+ JavaSource source;
+
+ public static void main(String[] args) {
+ JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ new T7190862().run(comp);
+ }
+
+ private void run(JavaCompiler comp) {
+ String code;
+ for (TypeWideInstructionMap typeInstructionMap: TypeWideInstructionMap.values()) {
+ if (typeInstructionMap != TypeWideInstructionMap.OBJECT) {
+ code = createWideLocalSource(typeInstructionMap.type, 300);
+ } else {
+ code = createWideLocalSourceForObject(300);
+ }
+ source = new JavaSource(code);
+ compile(comp);
+ check(typeInstructionMap.instructions);
+ }
+
+ //an extra test for the iinc instruction
+ code = createIincSource();
+ source = new JavaSource(code);
+ compile(comp);
+ check(new String[]{"iinc_w"});
+ }
+
+ private void compile(JavaCompiler comp) {
+ JavacTask ct = (JavacTask)comp.getTask(null, null, null, null, null, Arrays.asList(source));
+ try {
+ if (!ct.call()) {
+ throw new AssertionError("Error thrown when compiling the following source:\n" + source.getCharContent(true));
+ }
+ } catch (Throwable ex) {
+ throw new AssertionError("Error thrown when compiling the following source:\n" + source.getCharContent(true));
+ }
+ }
+
+ private void check(String[] instructions) {
+ String out = javap(Arrays.asList("-c"), Arrays.asList("Test.class"));
+ for (String line: out.split(System.getProperty("line.separator"))) {
+ line = line.trim();
+ for (String instruction: instructions) {
+ if (line.contains(instruction) && line.contains("#")) {
+ throw new Error("incorrect type for operands for instruction " + instruction);
+ }
+ }
+ }
+ }
+
+ private String javap(List<String> args, List<String> classes) {
+ DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<JavaFileObject>();
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ JavaFileManager fm = JavapFileManager.create(dc, pw);
+ JavapTask t = new JavapTask(pw, fm, dc, args, classes);
+ boolean ok = t.run();
+ if (!ok)
+ throw new Error("javap failed unexpectedly");
+
+ List<Diagnostic<? extends JavaFileObject>> diags = dc.getDiagnostics();
+ for (Diagnostic<? extends JavaFileObject> d: diags) {
+ if (d.getKind() == Diagnostic.Kind.ERROR)
+ throw new Error(d.getMessage(Locale.ENGLISH));
+ }
+ return sw.toString();
+
+ }
+
+ private String createWideLocalSource(String type, int numberOfVars) {
+ String result = " " + type + " x0 = 0;\n";
+ for (int i = 1; i < numberOfVars; i++) {
+ result += " " + type + " x" + i + " = x" + (i - 1) + " + 1;\n";
+ }
+ return result;
+ }
+
+ private String createWideLocalSourceForObject(int numberOfVars) {
+ String result = " Object x0 = new Object();\n";
+ for (int i = 1; i < numberOfVars; i++) {
+ result += " Object x" + i + " = x0;\n";
+ }
+ return result;
+ }
+
+ private String createIincSource() {
+ return " int i = 0;\n"
+ + " i += 1;\n"
+ + " i += 51;\n"
+ + " i += 101;\n"
+ + " i += 151;\n";
+ }
+
+ class JavaSource extends SimpleJavaFileObject {
+
+ String template = "class Test {\n" +
+ " public static void main(String[] args)\n" +
+ " {\n" +
+ " #C" +
+ " }\n" +
+ "}";
+
+ String source;
+
+ public JavaSource(String code) {
+ super(URI.create("Test.java"), JavaFileObject.Kind.SOURCE);
+ source = template.replaceAll("#C", code);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+ }
+}