Merge
This commit is contained in:
commit
e28423afe9
@ -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();
|
||||
}
|
@ -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}.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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 ?
|
||||
|
@ -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
|
||||
*************************************************************************/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 '<' it could be an unbound
|
||||
* method reference or a binary expression. To disambiguate, look for a
|
||||
* matching '>' and see if the subsequent terminal is either '.' or '#'.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
ParensResult analyzeParens() {
|
||||
int depth = 0;
|
||||
boolean type = false;
|
||||
for (int lookahead = 0 ; ; lookahead++) {
|
||||
TokenKind tk = S.token(lookahead).kind;
|
||||
switch (tk) {
|
||||
case EXTENDS: case SUPER: case COMMA:
|
||||
type = true;
|
||||
case QUES: case DOT: case AMP:
|
||||
//skip
|
||||
break;
|
||||
case BYTE: case SHORT: case INT: case LONG: case FLOAT:
|
||||
case DOUBLE: case BOOLEAN: case CHAR:
|
||||
if (peekToken(lookahead, RPAREN)) {
|
||||
//Type, ')' -> cast
|
||||
return ParensResult.CAST;
|
||||
} else if (peekToken(lookahead, IDENTIFIER)) {
|
||||
//Type, 'Identifier -> explicit lambda
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
}
|
||||
break;
|
||||
case LPAREN:
|
||||
if (lookahead != 0) {
|
||||
// '(' in a non-starting position -> parens
|
||||
return ParensResult.PARENS;
|
||||
} else if (peekToken(lookahead, RPAREN)) {
|
||||
// '(', ')' -> explicit lambda
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
}
|
||||
break;
|
||||
case RPAREN:
|
||||
// if we have seen something that looks like a type,
|
||||
// then it's a cast expression
|
||||
if (type) return ParensResult.CAST;
|
||||
// otherwise, disambiguate cast vs. parenthesized expression
|
||||
// based on subsequent token.
|
||||
switch (S.token(lookahead + 1).kind) {
|
||||
/*case PLUSPLUS: case SUBSUB: */
|
||||
case BANG: case TILDE:
|
||||
case LPAREN: case THIS: case SUPER:
|
||||
case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
|
||||
case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
|
||||
case TRUE: case FALSE: case NULL:
|
||||
case NEW: case IDENTIFIER: case ASSERT: case ENUM:
|
||||
case BYTE: case SHORT: case CHAR: case INT:
|
||||
case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
|
||||
return ParensResult.CAST;
|
||||
default:
|
||||
return ParensResult.PARENS;
|
||||
}
|
||||
case IDENTIFIER:
|
||||
if (peekToken(lookahead, IDENTIFIER)) {
|
||||
// Identifier, Identifier -> explicit lambda
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
} else if (peekToken(lookahead, RPAREN, ARROW)) {
|
||||
// Identifier, ')' '->' -> implicit lambda
|
||||
return ParensResult.IMPLICIT_LAMBDA;
|
||||
}
|
||||
break;
|
||||
case FINAL:
|
||||
case ELLIPSIS:
|
||||
case MONKEYS_AT:
|
||||
//those can only appear in explicit lambdas
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
case LBRACKET:
|
||||
if (peekToken(lookahead, RBRACKET, IDENTIFIER)) {
|
||||
// '[', ']', Identifier -> explicit lambda
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
} else if (peekToken(lookahead, RBRACKET, RPAREN) ||
|
||||
peekToken(lookahead, RBRACKET, AMP)) {
|
||||
// '[', ']', ')' -> cast
|
||||
// '[', ']', '&' -> cast (intersection type)
|
||||
return ParensResult.CAST;
|
||||
} else if (peekToken(lookahead, RBRACKET)) {
|
||||
//consume the ']' and skip
|
||||
type = true;
|
||||
lookahead++;
|
||||
break;
|
||||
} else {
|
||||
return ParensResult.PARENS;
|
||||
}
|
||||
case LT:
|
||||
depth++; break;
|
||||
case GTGTGT:
|
||||
depth--;
|
||||
case GTGT:
|
||||
depth--;
|
||||
case GT:
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
if (peekToken(lookahead, RPAREN) ||
|
||||
peekToken(lookahead, AMP)) {
|
||||
// '>', ')' -> cast
|
||||
// '>', '&' -> cast
|
||||
return ParensResult.CAST;
|
||||
} else if (peekToken(lookahead, IDENTIFIER, COMMA) ||
|
||||
peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) ||
|
||||
peekToken(lookahead, ELLIPSIS)) {
|
||||
// '>', Identifier, ',' -> explicit lambda
|
||||
// '>', Identifier, ')', '->' -> explicit lambda
|
||||
// '>', '...' -> explicit lambda
|
||||
return ParensResult.EXPLICIT_LAMBDA;
|
||||
}
|
||||
//it looks a type, but could still be (i) a cast to generic type,
|
||||
//(ii) an unbound method reference or (iii) an explicit lambda
|
||||
type = true;
|
||||
break;
|
||||
} else if (depth < 0) {
|
||||
//unbalanced '<', '>' - not a generic type
|
||||
return ParensResult.PARENS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//this includes EOF
|
||||
return ParensResult.PARENS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ParensResult {
|
||||
CAST,
|
||||
EXPLICIT_LAMBDA,
|
||||
IMPLICIT_LAMBDA,
|
||||
PARENS;
|
||||
}
|
||||
|
||||
JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
|
||||
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
|
||||
params.append(firstParam);
|
||||
@ -3171,21 +3264,12 @@ 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
|
||||
|
@ -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)
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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}
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @ignore 8004360
|
||||
* @bug 8003639
|
||||
* @summary convert lambda testng tests to jtreg and add them
|
||||
* @run testng DefaultMethodRegressionTests
|
@ -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;
|
||||
}
|
@ -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();
|
@ -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<?>)()->{};
|
||||
}
|
@ -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() { }
|
||||
}
|
@ -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() { }
|
||||
}
|
@ -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 &&
|
42
langtools/test/tools/javac/lambda/Intersection01.java
Normal file
42
langtools/test/tools/javac/lambda/Intersection01.java
Normal 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() { }
|
||||
}
|
3
langtools/test/tools/javac/lambda/Intersection01.out
Normal file
3
langtools/test/tools/javac/lambda/Intersection01.out
Normal 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
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
45
langtools/test/tools/javac/lambda/MethodReference55.java
Normal file
45
langtools/test/tools/javac/lambda/MethodReference55.java
Normal 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) { };
|
||||
}
|
3
langtools/test/tools/javac/lambda/MethodReference55.out
Normal file
3
langtools/test/tools/javac/lambda/MethodReference55.out
Normal 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
|
45
langtools/test/tools/javac/lambda/MethodReference56.java
Normal file
45
langtools/test/tools/javac/lambda/MethodReference56.java
Normal 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) { };
|
||||
}
|
3
langtools/test/tools/javac/lambda/MethodReference56.out
Normal file
3
langtools/test/tools/javac/lambda/MethodReference56.out
Normal 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
|
41
langtools/test/tools/javac/lambda/MethodReference57.java
Normal file
41
langtools/test/tools/javac/lambda/MethodReference57.java
Normal 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() { }
|
||||
}
|
46
langtools/test/tools/javac/lambda/MethodReference58.java
Normal file
46
langtools/test/tools/javac/lambda/MethodReference58.java
Normal 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) { }
|
||||
}
|
2
langtools/test/tools/javac/lambda/MethodReference58.out
Normal file
2
langtools/test/tools/javac/lambda/MethodReference58.out
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)");
|
||||
|
157
langtools/test/tools/javap/T7190862.java
Normal file
157
langtools/test/tools/javap/T7190862.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user