This commit is contained in:
Lana Steuck 2012-12-10 20:59:38 -08:00
commit e28423afe9
70 changed files with 2845 additions and 387 deletions

View File

@ -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();
}

View File

@ -246,6 +246,11 @@ public interface Tree {
*/
UNION_TYPE(UnionTypeTree.class),
/**
* Used for instances of {@link IntersectionTypeTree}.
*/
INTERSECTION_TYPE(IntersectionTypeTree.class),
/**
* Used for instances of {@link TypeCastTree}.
*/

View File

@ -98,6 +98,7 @@ public interface TreeVisitor<R,P> {
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);

View File

@ -240,6 +240,10 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
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);
}

View File

@ -371,6 +371,10 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
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;

View File

@ -71,11 +71,16 @@ public class Instruction {
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 @@ public class Instruction {
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 @@ public class Instruction {
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 @@ public class Instruction {
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);

View File

@ -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 @@ public enum Opcode {
// 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),

View File

@ -215,6 +215,9 @@ public enum Source {
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:

View File

@ -839,6 +839,49 @@ public class Type implements PrimitiveType {
}
}
// 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 {

View File

@ -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;
@ -382,28 +388,6 @@ public class Types {
}
}
/**
* 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
*/
@ -431,23 +415,8 @@ public class Types {
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 @@ public class Types {
}
// </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 @@ public class Types {
* @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 @@ public class Types {
* @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 @@ public class Types {
* 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 @@ public class Types {
* 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 @@ public class Types {
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);
}
}
}

View File

@ -716,21 +716,8 @@ public class Attr extends JCTree.Visitor {
}
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
}
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
//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 @@ public class Attr extends JCTree.Visitor {
}
}
}
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 @@ public class Attr extends JCTree.Visitor {
* 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 @@ public class Attr extends JCTree.Visitor {
}
}
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 @@ public class Attr extends JCTree.Visitor {
}
//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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
}
}
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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);

View File

@ -288,21 +288,20 @@ public class LambdaToMethod extends TreeTranslator {
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 @@ public class LambdaToMethod extends TreeTranslator {
//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);
}
}
/**

View File

@ -138,6 +138,10 @@ public class Lower extends TreeTranslator {
*/
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 @@ public class Lower extends TreeTranslator {
}
}
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 @@ public class Lower extends TreeTranslator {
// 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 @@ public class Lower extends TreeTranslator {
/** 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 @@ public class Lower extends TreeTranslator {
}
}
//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 @@ public class Lower extends TreeTranslator {
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);

View File

@ -2617,8 +2617,7 @@ public class Resolve {
@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 ?

View File

@ -551,6 +551,7 @@ public class TransTypes extends TreeTranslator {
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 @@ public class TransTypes extends TreeTranslator {
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 @@ public class TransTypes extends TreeTranslator {
result = clazz;
}
public void visitTypeIntersection(JCTypeIntersection tree) {
tree.bounds = translate(tree.bounds, null);
tree.type = erasure(tree.type);
result = tree;
}
/**************************************************************************
* utility methods
*************************************************************************/

View File

@ -846,17 +846,17 @@ public class ClassReader implements Completer {
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;
}

View File

@ -71,6 +71,7 @@ public class Gen extends JCTree.Visitor {
private final Map<Type,Symbol> stringBufferAppend;
private Name accessDollar;
private final Types types;
private final Lower lower;
/** Switch: GJ mode?
*/
@ -112,6 +113,7 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
}
}
/** 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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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 @@ public class Gen extends JCTree.Visitor {
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;

View File

@ -74,6 +74,7 @@ public class JavacTypes implements javax.lang.model.util.Types {
public Element asElement(TypeMirror t) {
switch (t.getKind()) {
case DECLARED:
case INTERSECTION:
case ERROR:
case TYPEVAR:
Type type = cast(Type.class, t);

View File

@ -348,8 +348,8 @@ public class JavaTokenizer {
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 @@ public class JavaTokenizer {
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 @@ public class JavaTokenizer {
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 @@ public class JavaTokenizer {
return;
}
}
reader.putChar(true);
} while (true);
}

View File

@ -124,6 +124,9 @@ public class JavacParser implements Parser {
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 @@ public class JavacParser implements Parser {
*/
boolean allowDefaultMethods;
/** Switch: should we allow intersection types in cast?
*/
boolean allowIntersectionTypesInCast;
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
@ -239,22 +246,38 @@ public class JavacParser implements Parser {
}
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 @@ public class JavacParser implements Parser {
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)
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);
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;
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 @@ public class JavacParser implements Parser {
}
}
/**
* If we see an identifier followed by a '&lt;' it could be an unbound
* method reference or a binary expression. To disambiguate, look for a
* matching '&gt;' 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 @@ public class JavacParser implements Parser {
/** 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 @@ public class JavacParser implements Parser {
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

View File

@ -187,8 +187,9 @@ compiler.misc.not.a.functional.intf.1=\
{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.descriptor.throws=\
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.err.invalid.mref=\
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 @@ compiler.err.default.methods.not.supported.in.source=\
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)

View File

@ -254,6 +254,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
*/
TYPEUNION,
/** Intersection types, of type TypeIntersection
*/
TYPEINTERSECTION,
/** Formal type parameters, of type TypeParameter.
*/
TYPEPARAMETER,
@ -1829,8 +1833,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
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 */
@ -2063,6 +2065,34 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
}
/**
* 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.
*/
@ -2385,6 +2415,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
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); }

View File

@ -1249,6 +1249,14 @@ public class Pretty extends JCTree.Visitor {
}
}
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);

View File

@ -358,6 +358,12 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
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);

View File

@ -267,6 +267,25 @@ public class TreeInfo {
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
*/

View File

@ -456,6 +456,12 @@ public class TreeMaker implements JCTree.Factory {
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;

View File

@ -286,6 +286,10 @@ public class TreeScanner extends Visitor {
scan(tree.alternatives);
}
public void visitTypeIntersection(JCTypeIntersection tree) {
scan(tree.bounds);
}
public void visitTypeParameter(JCTypeParameter tree) {
scan(tree.bounds);
}

View File

@ -379,6 +379,11 @@ public class TreeTranslator extends JCTree.Visitor {
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;

View File

@ -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();
}

View File

@ -144,7 +144,14 @@ public enum TypeKind {
*
* @since 1.7
*/
UNION;
UNION,
/**
* An intersection type.
*
* @since 1.8
*/
INTERSECTION;
/**
* Returns {@code true} if this kind corresponds to a primitive

View File

@ -172,4 +172,14 @@ public interface TypeVisitor<R, P> {
* @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);
}

View File

@ -110,6 +110,20 @@ public abstract class AbstractTypeVisitor6<R, P> implements TypeVisitor<R, P> {
return visitUnknown(t, p);
}
/**
* 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}
*

View File

@ -66,4 +66,13 @@ public abstract class AbstractTypeVisitor8<R, P> extends AbstractTypeVisitor7<R,
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);
}

View File

@ -108,8 +108,8 @@ import javax.annotation.processing.Processor;
* 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 @@ import javax.annotation.processing.Processor;
* 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");

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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 {}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -25,6 +25,7 @@
/**
* @test
* @ignore 8004360
* @bug 8003639
* @summary convert lambda testng tests to jtreg and add them
* @run testng DefaultMethodRegressionTests

View File

@ -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;
}

View File

@ -22,9 +22,9 @@
*/
// key: compiler.err.prob.found.req
// key: compiler.misc.invalid.generic.desc.in.functional.intf
// key: compiler.misc.invalid.generic.lambda.target
class InvalidGenericDescInFunctionalIntf {
class InvalidGenericLambdaTarget {
interface SAM {
<Z> void m();

View File

@ -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<?>)()->{};
}

View File

@ -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() { }
}

View File

@ -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() { }
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,11 +23,11 @@
/**
* @test
* @bug 8003280
* @bug 8003280 8004102
* @summary Add lambda tests
* perform several automated checks in lambda conversion, esp. around accessibility
* @author Maurizio Cimadamore
* @run main LambdaConversionTest
* @run main FunctionalInterfaceConversionTest
*/
import com.sun.source.util.JavacTask;
@ -37,9 +37,10 @@ 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 LambdaConversionTest {
public class FunctionalInterfaceConversionTest {
enum PackageKind {
NO_PKG(""),
@ -108,10 +109,21 @@ public class LambdaConversionTest {
}
}
enum ExprKind {
LAMBDA("x -> null"),
MREF("this::m");
String exprStr;
private ExprKind(String exprStr) {
this.exprStr = exprStr;
}
}
enum MethodKind {
NONE(""),
NON_GENERIC("public #R m(#ARG s) throws #T;"),
GENERIC("public <X> #R m(#ARG s) throws #T;");
NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
String methodTemplate;
@ -127,15 +139,21 @@ public class LambdaConversionTest {
}
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 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();
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);
}
}
}
}
}
@ -148,15 +166,18 @@ public class LambdaConversionTest {
PackageKind samPkg;
ModifierKind modKind;
SamKind samKind;
MethodKind meth;
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(meth.getMethod(retType, argType, thrownType)));
replaceAll("#C", samKind.getSam(samMeth.getMethod(retType, argType, thrownType)));
}
};
@ -169,27 +190,33 @@ public class LambdaConversionTest {
};
SourceFile clientSourceFile = new SourceFile("Client.java",
"#I\n class Client { Sam s = x -> null; }") {
"#I\n abstract class Client { \n" +
" Sam s = #E;\n" +
" #M \n }") {
public String toString() {
return template.replaceAll("#I", samPkg.getImportStat());
return template.replaceAll("#I", samPkg.getImportStat())
.replaceAll("#E", exprKind.exprStr)
.replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
}
};
LambdaConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
MethodKind meth, TypeKind retType, TypeKind argType, TypeKind 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.meth = meth;
this.samMeth = samMeth;
this.clientMeth = clientMeth;
this.retType = retType;
this.argType = argType;
this.thrownType = thrownType;
this.exprKind = exprKind;
this.dc = new DiagnosticChecker();
}
void test() throws Exception {
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
DiagnosticChecker dc = new DiagnosticChecker();
JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
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()) {
@ -201,8 +228,15 @@ public class LambdaConversionTest {
if (samKind != SamKind.INTERFACE) {
//sam type must be an interface
return false;
} else if (meth != MethodKind.NON_GENERIC) {
//target method must be non-generic
} 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 &&

View File

@ -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() { }
}

View File

@ -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

View File

@ -23,7 +23,7 @@ class LambdaConv21 {
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
}

View File

@ -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

View File

@ -90,9 +90,14 @@ public class LambdaParserTest {
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 @@ public class LambdaParserTest {
boolean explicit() {
return this != IMPLICIT;
}
boolean isVarargs() {
return this == EXPLICIT_VARARGS ||
this == EXPLICIT_GENERIC2_VARARGS;
}
}
enum ModifierKind {
@ -253,7 +263,7 @@ public class LambdaParserTest {
if (lk.arity() == 2 &&
(pk1.explicit() != pk2.explicit() ||
pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) {
pk1.isVarargs())) {
errorExpected = true;
}

View File

@ -46,7 +46,7 @@ public class MethodReference30 {
assertTrue(true);
}
static void m() { }
void m() { }
public static void main(String[] args) {
SAM s = new MethodReference30()::m;

View File

@ -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) { };
}

View File

@ -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

View File

@ -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) { };
}

View File

@ -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

View File

@ -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() { }
}

View File

@ -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) { }
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -70,9 +70,6 @@ public class MethodRef1 {
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);

View File

@ -133,15 +133,6 @@ public class SamConversion {
} catch (Exception e) {
assertTrue(false);
}
bar = new A()::method6;
try {
bar.m(1);
assertTrue(false);
} catch (MyException e) {
} catch (Exception e) {
assertTrue(false);
}
}
/**

View File

@ -119,20 +119,6 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
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 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
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)");

View File

@ -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;
}
}
}