mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
Merge
This commit is contained in:
commit
be00b8110f
21 changed files with 1043 additions and 84 deletions
|
@ -219,3 +219,4 @@ e19283cd30a43fca94d8f7639c73ef66db493b1e jdk8-b90
|
||||||
4cb1136231275a1f8af53f5bfdef0b488e4b5bab jdk8-b95
|
4cb1136231275a1f8af53f5bfdef0b488e4b5bab jdk8-b95
|
||||||
988aef3a8c3adac482363293f65e77ec4c5ce98d jdk8-b96
|
988aef3a8c3adac482363293f65e77ec4c5ce98d jdk8-b96
|
||||||
6a11a81a8824c17f6cd2ec8f8492e1229b694e96 jdk8-b97
|
6a11a81a8824c17f6cd2ec8f8492e1229b694e96 jdk8-b97
|
||||||
|
ce5a90df517bdceb2739d7dd3e6764b070def802 jdk8-b98
|
||||||
|
|
|
@ -33,10 +33,15 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
|
||||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||||
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
|
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
|
||||||
|
import com.sun.tools.javac.comp.AttrContext;
|
||||||
import com.sun.tools.javac.comp.Check;
|
import com.sun.tools.javac.comp.Check;
|
||||||
|
import com.sun.tools.javac.comp.Enter;
|
||||||
|
import com.sun.tools.javac.comp.Env;
|
||||||
import com.sun.tools.javac.jvm.ClassReader;
|
import com.sun.tools.javac.jvm.ClassReader;
|
||||||
import com.sun.tools.javac.util.*;
|
import com.sun.tools.javac.util.*;
|
||||||
import static com.sun.tools.javac.code.BoundKind.*;
|
import static com.sun.tools.javac.code.BoundKind.*;
|
||||||
|
@ -83,6 +88,7 @@ public class Types {
|
||||||
final boolean allowDefaultMethods;
|
final boolean allowDefaultMethods;
|
||||||
final ClassReader reader;
|
final ClassReader reader;
|
||||||
final Check chk;
|
final Check chk;
|
||||||
|
final Enter enter;
|
||||||
JCDiagnostic.Factory diags;
|
JCDiagnostic.Factory diags;
|
||||||
List<Warner> warnStack = List.nil();
|
List<Warner> warnStack = List.nil();
|
||||||
final Name capturedName;
|
final Name capturedName;
|
||||||
|
@ -109,6 +115,7 @@ public class Types {
|
||||||
allowDefaultMethods = source.allowDefaultMethods();
|
allowDefaultMethods = source.allowDefaultMethods();
|
||||||
reader = ClassReader.instance(context);
|
reader = ClassReader.instance(context);
|
||||||
chk = Check.instance(context);
|
chk = Check.instance(context);
|
||||||
|
enter = Enter.instance(context);
|
||||||
capturedName = names.fromString("<captured wildcard>");
|
capturedName = names.fromString("<captured wildcard>");
|
||||||
messages = JavacMessages.instance(context);
|
messages = JavacMessages.instance(context);
|
||||||
diags = JCDiagnostic.Factory.instance(context);
|
diags = JCDiagnostic.Factory.instance(context);
|
||||||
|
@ -605,6 +612,84 @@ public class Types {
|
||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a symbol for a class that implements a given functional interface
|
||||||
|
* and overrides its functional descriptor. This routine is used for two
|
||||||
|
* main purposes: (i) checking well-formedness of a functional interface;
|
||||||
|
* (ii) perform functional interface bridge calculation.
|
||||||
|
*/
|
||||||
|
public ClassSymbol makeFunctionalInterfaceClass(Env<AttrContext> env, Name name, List<Type> targets, long cflags) {
|
||||||
|
Assert.check(targets.nonEmpty() && isFunctionalInterface(targets.head));
|
||||||
|
Symbol descSym = findDescriptorSymbol(targets.head.tsym);
|
||||||
|
Type descType = findDescriptorType(targets.head);
|
||||||
|
ClassSymbol csym = new ClassSymbol(cflags, name, env.enclClass.sym.outermostClass());
|
||||||
|
csym.completer = null;
|
||||||
|
csym.members_field = new Scope(csym);
|
||||||
|
MethodSymbol instDescSym = new MethodSymbol(descSym.flags(), descSym.name, descType, csym);
|
||||||
|
csym.members_field.enter(instDescSym);
|
||||||
|
Type.ClassType ctype = new Type.ClassType(Type.noType, List.<Type>nil(), csym);
|
||||||
|
ctype.supertype_field = syms.objectType;
|
||||||
|
ctype.interfaces_field = targets;
|
||||||
|
csym.type = ctype;
|
||||||
|
csym.sourcefile = ((ClassSymbol)csym.owner).sourcefile;
|
||||||
|
return csym;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the minimal set of methods that are overridden by the functional
|
||||||
|
* descriptor in 'origin'. All returned methods are assumed to have different
|
||||||
|
* erased signatures.
|
||||||
|
*/
|
||||||
|
public List<Symbol> functionalInterfaceBridges(TypeSymbol origin) {
|
||||||
|
Assert.check(isFunctionalInterface(origin));
|
||||||
|
Symbol descSym = findDescriptorSymbol(origin);
|
||||||
|
CompoundScope members = membersClosure(origin.type, false);
|
||||||
|
ListBuffer<Symbol> overridden = ListBuffer.lb();
|
||||||
|
outer: for (Symbol m2 : members.getElementsByName(descSym.name, bridgeFilter)) {
|
||||||
|
if (m2 == descSym) continue;
|
||||||
|
else if (descSym.overrides(m2, origin, Types.this, false)) {
|
||||||
|
for (Symbol m3 : overridden) {
|
||||||
|
if (isSameType(m3.erasure(Types.this), m2.erasure(Types.this)) ||
|
||||||
|
(m3.overrides(m2, origin, Types.this, false) &&
|
||||||
|
(pendingBridges((ClassSymbol)origin, m3.enclClass()) ||
|
||||||
|
(((MethodSymbol)m2).binaryImplementation((ClassSymbol)m3.owner, Types.this) != null)))) {
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overridden.add(m2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overridden.toList();
|
||||||
|
}
|
||||||
|
//where
|
||||||
|
private Filter<Symbol> bridgeFilter = new Filter<Symbol>() {
|
||||||
|
public boolean accepts(Symbol t) {
|
||||||
|
return t.kind == Kinds.MTH &&
|
||||||
|
t.name != names.init &&
|
||||||
|
t.name != names.clinit &&
|
||||||
|
(t.flags() & SYNTHETIC) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private boolean pendingBridges(ClassSymbol origin, TypeSymbol s) {
|
||||||
|
//a symbol will be completed from a classfile if (a) symbol has
|
||||||
|
//an associated file object with CLASS kind and (b) the symbol has
|
||||||
|
//not been entered
|
||||||
|
if (origin.classfile != null &&
|
||||||
|
origin.classfile.getKind() == JavaFileObject.Kind.CLASS &&
|
||||||
|
enter.getEnv(origin) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (origin == s) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Type t : interfaces(origin.type)) {
|
||||||
|
if (pendingBridges((ClassSymbol)t.tsym, s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2672,6 +2757,7 @@ public class Types {
|
||||||
public boolean accepts(Symbol s) {
|
public boolean accepts(Symbol s) {
|
||||||
return s.kind == Kinds.MTH &&
|
return s.kind == Kinds.MTH &&
|
||||||
s.name == msym.name &&
|
s.name == msym.name &&
|
||||||
|
(s.flags() & SYNTHETIC) == 0 &&
|
||||||
s.isInheritedIn(site.tsym, Types.this) &&
|
s.isInheritedIn(site.tsym, Types.this) &&
|
||||||
overrideEquivalent(memberType(site, s), memberType(site, msym));
|
overrideEquivalent(memberType(site, s), memberType(site, msym));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2330,13 +2330,12 @@ public class Attr extends JCTree.Visitor {
|
||||||
if (pt() != Type.recoveryType) {
|
if (pt() != Type.recoveryType) {
|
||||||
target = targetChecker.visit(target, that);
|
target = targetChecker.visit(target, that);
|
||||||
lambdaType = types.findDescriptorType(target);
|
lambdaType = types.findDescriptorType(target);
|
||||||
chk.checkFunctionalInterface(that, target);
|
|
||||||
} else {
|
} else {
|
||||||
target = Type.recoveryType;
|
target = Type.recoveryType;
|
||||||
lambdaType = fallbackDescriptorType(that);
|
lambdaType = fallbackDescriptorType(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFunctionalInfo(that, pt(), lambdaType, target, resultInfo.checkContext.inferenceContext());
|
setFunctionalInfo(localEnv, that, pt(), lambdaType, target, resultInfo.checkContext);
|
||||||
|
|
||||||
if (lambdaType.hasTag(FORALL)) {
|
if (lambdaType.hasTag(FORALL)) {
|
||||||
//lambda expression target desc cannot be a generic method
|
//lambda expression target desc cannot be a generic method
|
||||||
|
@ -2715,13 +2714,12 @@ public class Attr extends JCTree.Visitor {
|
||||||
if (pt() != Type.recoveryType) {
|
if (pt() != Type.recoveryType) {
|
||||||
target = targetChecker.visit(pt(), that);
|
target = targetChecker.visit(pt(), that);
|
||||||
desc = types.findDescriptorType(target);
|
desc = types.findDescriptorType(target);
|
||||||
chk.checkFunctionalInterface(that, target);
|
|
||||||
} else {
|
} else {
|
||||||
target = Type.recoveryType;
|
target = Type.recoveryType;
|
||||||
desc = fallbackDescriptorType(that);
|
desc = fallbackDescriptorType(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
|
setFunctionalInfo(localEnv, that, pt(), desc, target, resultInfo.checkContext);
|
||||||
List<Type> argtypes = desc.getParameterTypes();
|
List<Type> argtypes = desc.getParameterTypes();
|
||||||
Resolve.MethodCheck referenceCheck = rs.resolveMethodCheck;
|
Resolve.MethodCheck referenceCheck = rs.resolveMethodCheck;
|
||||||
|
|
||||||
|
@ -2941,31 +2939,37 @@ public class Attr extends JCTree.Visitor {
|
||||||
* might contain inference variables, we might need to register an hook in the
|
* might contain inference variables, we might need to register an hook in the
|
||||||
* current inference context.
|
* current inference context.
|
||||||
*/
|
*/
|
||||||
private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt,
|
private void setFunctionalInfo(final Env<AttrContext> env, final JCFunctionalExpression fExpr,
|
||||||
final Type descriptorType, final Type primaryTarget, InferenceContext inferenceContext) {
|
final Type pt, final Type descriptorType, final Type primaryTarget, final CheckContext checkContext) {
|
||||||
if (inferenceContext.free(descriptorType)) {
|
if (checkContext.inferenceContext().free(descriptorType)) {
|
||||||
inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
|
checkContext.inferenceContext().addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
|
||||||
public void typesInferred(InferenceContext inferenceContext) {
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType),
|
setFunctionalInfo(env, fExpr, pt, inferenceContext.asInstType(descriptorType),
|
||||||
inferenceContext.asInstType(primaryTarget), inferenceContext);
|
inferenceContext.asInstType(primaryTarget), checkContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ListBuffer<TypeSymbol> targets = ListBuffer.lb();
|
ListBuffer<Type> targets = ListBuffer.lb();
|
||||||
if (pt.hasTag(CLASS)) {
|
if (pt.hasTag(CLASS)) {
|
||||||
if (pt.isCompound()) {
|
if (pt.isCompound()) {
|
||||||
targets.append(primaryTarget.tsym); //this goes first
|
targets.append(types.removeWildcards(primaryTarget)); //this goes first
|
||||||
for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
|
for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
|
||||||
if (t != primaryTarget) {
|
if (t != primaryTarget) {
|
||||||
targets.append(t.tsym);
|
targets.append(types.removeWildcards(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
targets.append(pt.tsym);
|
targets.append(types.removeWildcards(primaryTarget));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fExpr.targets = targets.toList();
|
fExpr.targets = targets.toList();
|
||||||
fExpr.descriptorType = descriptorType;
|
if (checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
|
||||||
|
pt != Type.recoveryType) {
|
||||||
|
//check that functional interface class is well-formed
|
||||||
|
ClassSymbol csym = types.makeFunctionalInterfaceClass(env,
|
||||||
|
names.empty, List.of(fExpr.targets.head), ABSTRACT);
|
||||||
|
chk.checkImplementations(env.tree, csym, csym);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4644,9 +4648,6 @@ public class Attr extends JCTree.Visitor {
|
||||||
@Override
|
@Override
|
||||||
public void visitLambda(JCLambda that) {
|
public void visitLambda(JCLambda that) {
|
||||||
super.visitLambda(that);
|
super.visitLambda(that);
|
||||||
if (that.descriptorType == null) {
|
|
||||||
that.descriptorType = syms.unknownType;
|
|
||||||
}
|
|
||||||
if (that.targets == null) {
|
if (that.targets == null) {
|
||||||
that.targets = List.nil();
|
that.targets = List.nil();
|
||||||
}
|
}
|
||||||
|
@ -4658,9 +4659,6 @@ public class Attr extends JCTree.Visitor {
|
||||||
if (that.sym == null) {
|
if (that.sym == null) {
|
||||||
that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol);
|
that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol);
|
||||||
}
|
}
|
||||||
if (that.descriptorType == null) {
|
|
||||||
that.descriptorType = syms.unknownType;
|
|
||||||
}
|
|
||||||
if (that.targets == null) {
|
if (that.targets == null) {
|
||||||
that.targets = List.nil();
|
that.targets = List.nil();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2276,24 +2276,6 @@ public class Check {
|
||||||
c.flags_field |= ACYCLIC;
|
c.flags_field |= ACYCLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check that functional interface methods would make sense when seen
|
|
||||||
* from the perspective of the implementing class
|
|
||||||
*/
|
|
||||||
void checkFunctionalInterface(JCTree tree, Type funcInterface) {
|
|
||||||
ClassType c = new ClassType(Type.noType, List.<Type>nil(), null);
|
|
||||||
ClassSymbol csym = new ClassSymbol(0, names.empty, c, syms.noSymbol);
|
|
||||||
c.interfaces_field = List.of(types.removeWildcards(funcInterface));
|
|
||||||
c.supertype_field = syms.objectType;
|
|
||||||
c.tsym = csym;
|
|
||||||
csym.members_field = new Scope(csym);
|
|
||||||
Symbol descSym = types.findDescriptorSymbol(funcInterface.tsym);
|
|
||||||
Type descType = types.findDescriptorType(funcInterface);
|
|
||||||
csym.members_field.enter(new MethodSymbol(PUBLIC, descSym.name, descType, csym));
|
|
||||||
csym.completer = null;
|
|
||||||
checkImplementations(tree, csym, csym);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check that all methods which implement some
|
/** Check that all methods which implement some
|
||||||
* method conform to the method they implement.
|
* method conform to the method they implement.
|
||||||
* @param tree The class definition whose members are checked.
|
* @param tree The class definition whose members are checked.
|
||||||
|
|
|
@ -100,6 +100,9 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
/** Flag for alternate metafactories indicating the lambda object has multiple targets */
|
/** Flag for alternate metafactories indicating the lambda object has multiple targets */
|
||||||
public static final int FLAG_MARKERS = 1 << 1;
|
public static final int FLAG_MARKERS = 1 << 1;
|
||||||
|
|
||||||
|
/** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
|
||||||
|
public static final int FLAG_BRIDGES = 1 << 2;
|
||||||
|
|
||||||
private class KlassInfo {
|
private class KlassInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,7 +324,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
int refKind = referenceKind(sym);
|
int refKind = referenceKind(sym);
|
||||||
|
|
||||||
//convert to an invokedynamic call
|
//convert to an invokedynamic call
|
||||||
result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
|
result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JCIdent makeThis(Type type, Symbol owner) {
|
private JCIdent makeThis(Type type, Symbol owner) {
|
||||||
|
@ -382,7 +385,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
|
|
||||||
|
|
||||||
//build a sam instance using an indy call to the meta-factory
|
//build a sam instance using an indy call to the meta-factory
|
||||||
result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
|
result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -606,8 +609,8 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
make.Return(makeIndyCall(
|
make.Return(makeIndyCall(
|
||||||
pos,
|
pos,
|
||||||
syms.lambdaMetafactory,
|
syms.lambdaMetafactory,
|
||||||
names.altMetaFactory,
|
names.altMetafactory,
|
||||||
staticArgs, indyType, serArgs.toList())),
|
staticArgs, indyType, serArgs.toList(), samSym.name)),
|
||||||
null);
|
null);
|
||||||
ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
|
ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
|
||||||
if (stmts == null) {
|
if (stmts == null) {
|
||||||
|
@ -905,22 +908,26 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
|
kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MethodType typeToMethodType(Type mt) {
|
||||||
|
Type type = types.erasure(mt);
|
||||||
|
return new MethodType(type.getParameterTypes(),
|
||||||
|
type.getReturnType(),
|
||||||
|
type.getThrownTypes(),
|
||||||
|
syms.methodClass);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an indy method call to the meta factory
|
* Generate an indy method call to the meta factory
|
||||||
*/
|
*/
|
||||||
private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
|
private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
|
||||||
boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
|
int refKind, Symbol refSym, List<JCExpression> indy_args) {
|
||||||
|
JCFunctionalExpression tree = context.tree;
|
||||||
//determine the static bsm args
|
//determine the static bsm args
|
||||||
Type mtype = types.erasure(tree.descriptorType);
|
|
||||||
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
|
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
|
||||||
List<Object> staticArgs = List.<Object>of(
|
List<Object> staticArgs = List.<Object>of(
|
||||||
new Pool.MethodHandle(ClassFile.REF_invokeInterface,
|
typeToMethodType(samSym.type),
|
||||||
types.findDescriptorSymbol(tree.type.tsym), types),
|
|
||||||
new Pool.MethodHandle(refKind, refSym, types),
|
new Pool.MethodHandle(refKind, refSym, types),
|
||||||
new MethodType(mtype.getParameterTypes(),
|
typeToMethodType(tree.getDescriptorType(types)));
|
||||||
mtype.getReturnType(),
|
|
||||||
mtype.getThrownTypes(),
|
|
||||||
syms.methodClass));
|
|
||||||
|
|
||||||
//computed indy arg types
|
//computed indy arg types
|
||||||
ListBuffer<Type> indy_args_types = ListBuffer.lb();
|
ListBuffer<Type> indy_args_types = ListBuffer.lb();
|
||||||
|
@ -934,31 +941,46 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
List.<Type>nil(),
|
List.<Type>nil(),
|
||||||
syms.methodClass);
|
syms.methodClass);
|
||||||
|
|
||||||
Name metafactoryName = needsAltMetafactory ?
|
Name metafactoryName = context.needsAltMetafactory() ?
|
||||||
names.altMetaFactory : names.metaFactory;
|
names.altMetafactory : names.metafactory;
|
||||||
|
|
||||||
if (needsAltMetafactory) {
|
if (context.needsAltMetafactory()) {
|
||||||
ListBuffer<Object> markers = ListBuffer.lb();
|
ListBuffer<Object> markers = ListBuffer.lb();
|
||||||
for (Symbol t : tree.targets.tail) {
|
for (Type t : tree.targets.tail) {
|
||||||
if (t != syms.serializableType.tsym) {
|
if (t.tsym != syms.serializableType.tsym) {
|
||||||
markers.append(t);
|
markers.append(t.tsym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int flags = isSerializable? FLAG_SERIALIZABLE : 0;
|
int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
|
||||||
boolean hasMarkers = markers.nonEmpty();
|
boolean hasMarkers = markers.nonEmpty();
|
||||||
flags |= hasMarkers ? FLAG_MARKERS : 0;
|
boolean hasBridges = context.bridges.nonEmpty();
|
||||||
|
if (hasMarkers) {
|
||||||
|
flags |= FLAG_MARKERS;
|
||||||
|
}
|
||||||
|
if (hasBridges) {
|
||||||
|
flags |= FLAG_BRIDGES;
|
||||||
|
}
|
||||||
staticArgs = staticArgs.append(flags);
|
staticArgs = staticArgs.append(flags);
|
||||||
if (hasMarkers) {
|
if (hasMarkers) {
|
||||||
staticArgs = staticArgs.append(markers.length());
|
staticArgs = staticArgs.append(markers.length());
|
||||||
staticArgs = staticArgs.appendList(markers.toList());
|
staticArgs = staticArgs.appendList(markers.toList());
|
||||||
}
|
}
|
||||||
if (isSerializable) {
|
if (hasBridges) {
|
||||||
|
staticArgs = staticArgs.append(context.bridges.length() - 1);
|
||||||
|
for (Symbol s : context.bridges) {
|
||||||
|
Type s_erasure = s.erasure(types);
|
||||||
|
if (!types.isSameType(s_erasure, samSym.erasure(types))) {
|
||||||
|
staticArgs = staticArgs.append(s.erasure(types));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context.isSerializable()) {
|
||||||
addDeserializationCase(refKind, refSym, tree.type, samSym,
|
addDeserializationCase(refKind, refSym, tree.type, samSym,
|
||||||
tree, staticArgs, indyType);
|
tree, staticArgs, indyType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
|
return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -966,7 +988,8 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
* arguments types
|
* arguments types
|
||||||
*/
|
*/
|
||||||
private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
|
private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
|
||||||
List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
|
List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
|
||||||
|
Name methName) {
|
||||||
int prevPos = make.pos;
|
int prevPos = make.pos;
|
||||||
try {
|
try {
|
||||||
make.at(pos);
|
make.at(pos);
|
||||||
|
@ -978,7 +1001,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
bsmName, bsm_staticArgs, List.<Type>nil());
|
bsmName, bsm_staticArgs, List.<Type>nil());
|
||||||
|
|
||||||
DynamicMethodSymbol dynSym =
|
DynamicMethodSymbol dynSym =
|
||||||
new DynamicMethodSymbol(names.lambda,
|
new DynamicMethodSymbol(methName,
|
||||||
syms.noSymbol,
|
syms.noSymbol,
|
||||||
bsm.isStatic() ?
|
bsm.isStatic() ?
|
||||||
ClassFile.REF_invokeStatic :
|
ClassFile.REF_invokeStatic :
|
||||||
|
@ -1299,7 +1322,6 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
|
|
||||||
// Make lambda holding the new-class call
|
// Make lambda holding the new-class call
|
||||||
JCLambda slam = make.Lambda(params, nc);
|
JCLambda slam = make.Lambda(params, nc);
|
||||||
slam.descriptorType = tree.descriptorType;
|
|
||||||
slam.targets = tree.targets;
|
slam.targets = tree.targets;
|
||||||
slam.type = tree.type;
|
slam.type = tree.type;
|
||||||
slam.pos = tree.pos;
|
slam.pos = tree.pos;
|
||||||
|
@ -1634,23 +1656,30 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
/** the enclosing translation context (set for nested lambdas/mref) */
|
/** the enclosing translation context (set for nested lambdas/mref) */
|
||||||
TranslationContext<?> prev;
|
TranslationContext<?> prev;
|
||||||
|
|
||||||
|
/** list of methods to be bridged by the meta-factory */
|
||||||
|
List<Symbol> bridges;
|
||||||
|
|
||||||
TranslationContext(T tree) {
|
TranslationContext(T tree) {
|
||||||
this.tree = tree;
|
this.tree = tree;
|
||||||
this.owner = owner();
|
this.owner = owner();
|
||||||
this.depth = frameStack.size() - 1;
|
this.depth = frameStack.size() - 1;
|
||||||
this.prev = context();
|
this.prev = context();
|
||||||
|
ClassSymbol csym =
|
||||||
|
types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
|
||||||
|
this.bridges = types.functionalInterfaceBridges(csym);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** does this functional expression need to be created using alternate metafactory? */
|
/** does this functional expression need to be created using alternate metafactory? */
|
||||||
boolean needsAltMetafactory() {
|
boolean needsAltMetafactory() {
|
||||||
return (tree.targets.length() > 1 ||
|
return tree.targets.length() > 1 ||
|
||||||
isSerializable());
|
isSerializable() ||
|
||||||
|
bridges.length() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** does this functional expression require serialization support? */
|
/** does this functional expression require serialization support? */
|
||||||
boolean isSerializable() {
|
boolean isSerializable() {
|
||||||
for (Symbol target : tree.targets) {
|
for (Type target : tree.targets) {
|
||||||
if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
|
if (types.asSuper(target, syms.serializableType.tsym) != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1862,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
Type generatedLambdaSig() {
|
Type generatedLambdaSig() {
|
||||||
return types.erasure(tree.descriptorType);
|
return types.erasure(tree.getDescriptorType(types));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1909,7 +1938,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
Type bridgedRefSig() {
|
Type bridgedRefSig() {
|
||||||
return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
|
return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ public class TransTypes extends TreeTranslator {
|
||||||
private TreeMaker make;
|
private TreeMaker make;
|
||||||
private Enter enter;
|
private Enter enter;
|
||||||
private boolean allowEnums;
|
private boolean allowEnums;
|
||||||
|
private boolean allowInterfaceBridges;
|
||||||
private Types types;
|
private Types types;
|
||||||
private final Resolve resolve;
|
private final Resolve resolve;
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ public class TransTypes extends TreeTranslator {
|
||||||
Source source = Source.instance(context);
|
Source source = Source.instance(context);
|
||||||
allowEnums = source.allowEnums();
|
allowEnums = source.allowEnums();
|
||||||
addBridges = source.addBridges();
|
addBridges = source.addBridges();
|
||||||
|
allowInterfaceBridges = source.allowDefaultMethods();
|
||||||
types = Types.instance(context);
|
types = Types.instance(context);
|
||||||
make = TreeMaker.instance(context);
|
make = TreeMaker.instance(context);
|
||||||
resolve = Resolve.instance(context);
|
resolve = Resolve.instance(context);
|
||||||
|
@ -252,7 +254,8 @@ public class TransTypes extends TreeTranslator {
|
||||||
|
|
||||||
// Create a bridge method symbol and a bridge definition without a body.
|
// Create a bridge method symbol and a bridge definition without a body.
|
||||||
Type bridgeType = meth.erasure(types);
|
Type bridgeType = meth.erasure(types);
|
||||||
long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
|
long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
|
||||||
|
(origin.isInterface() ? DEFAULT : 0);
|
||||||
if (hypothetical) flags |= HYPOTHETICAL;
|
if (hypothetical) flags |= HYPOTHETICAL;
|
||||||
MethodSymbol bridge = new MethodSymbol(flags,
|
MethodSymbol bridge = new MethodSymbol(flags,
|
||||||
meth.name,
|
meth.name,
|
||||||
|
@ -387,11 +390,12 @@ public class TransTypes extends TreeTranslator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// where
|
// where
|
||||||
Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
|
private Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
|
||||||
public boolean accepts(Symbol s) {
|
public boolean accepts(Symbol s) {
|
||||||
return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
|
return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param method The symbol for which a bridge might have to be added
|
* @param method The symbol for which a bridge might have to be added
|
||||||
* @param impl The implementation of method
|
* @param impl The implementation of method
|
||||||
|
@ -999,8 +1003,9 @@ public class TransTypes extends TreeTranslator {
|
||||||
ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
|
ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
|
||||||
if (false) //see CR: 6996415
|
if (false) //see CR: 6996415
|
||||||
bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
|
bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
|
||||||
if ((tree.sym.flags() & INTERFACE) == 0)
|
if (allowInterfaceBridges || (tree.sym.flags() & INTERFACE) == 0) {
|
||||||
addBridges(tree.pos(), tree.sym, bridges);
|
addBridges(tree.pos(), c, bridges);
|
||||||
|
}
|
||||||
tree.defs = bridges.toList().prependList(tree.defs);
|
tree.defs = bridges.toList().prependList(tree.defs);
|
||||||
}
|
}
|
||||||
tree.type = erasure(tree.type);
|
tree.type = erasure(tree.type);
|
||||||
|
|
|
@ -641,10 +641,12 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||||
polyKind = PolyKind.POLY;
|
polyKind = PolyKind.POLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** target descriptor inferred for this functional expression. */
|
|
||||||
public Type descriptorType;
|
|
||||||
/** list of target types inferred for this functional expression. */
|
/** list of target types inferred for this functional expression. */
|
||||||
public List<TypeSymbol> targets;
|
public List<Type> targets;
|
||||||
|
|
||||||
|
public Type getDescriptorType(Types types) {
|
||||||
|
return types.findDescriptorType(targets.head);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -174,8 +174,8 @@ public class Names {
|
||||||
|
|
||||||
//lambda-related
|
//lambda-related
|
||||||
public final Name lambda;
|
public final Name lambda;
|
||||||
public final Name metaFactory;
|
public final Name metafactory;
|
||||||
public final Name altMetaFactory;
|
public final Name altMetafactory;
|
||||||
|
|
||||||
public final Name.Table table;
|
public final Name.Table table;
|
||||||
|
|
||||||
|
@ -310,8 +310,8 @@ public class Names {
|
||||||
|
|
||||||
//lambda-related
|
//lambda-related
|
||||||
lambda = fromString("lambda$");
|
lambda = fromString("lambda$");
|
||||||
metaFactory = fromString("metaFactory");
|
metafactory = fromString("metafactory");
|
||||||
altMetaFactory = fromString("altMetaFactory");
|
altMetafactory = fromString("altMetafactory");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Name.Table createTable(Options options) {
|
protected Name.Table createTable(Options options) {
|
||||||
|
|
28
langtools/test/tools/javac/generics/bridges/Bridge.java
Normal file
28
langtools/test/tools/javac/generics/bridges/Bridge.java
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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 java.lang.annotation.Repeatable;
|
||||||
|
|
||||||
|
@Repeatable(Bridges.class)
|
||||||
|
@interface Bridge {
|
||||||
|
String value();
|
||||||
|
}
|
218
langtools/test/tools/javac/generics/bridges/BridgeHarness.java
Normal file
218
langtools/test/tools/javac/generics/bridges/BridgeHarness.java
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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 8013789
|
||||||
|
* @summary Compiler should emit bridges in interfaces
|
||||||
|
* @library /tools/javac/lib
|
||||||
|
* @build JavacTestingAbstractProcessor BridgeHarness
|
||||||
|
* @run main BridgeHarness
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.source.util.JavacTask;
|
||||||
|
import com.sun.tools.classfile.AccessFlags;
|
||||||
|
import com.sun.tools.classfile.ClassFile;
|
||||||
|
import com.sun.tools.classfile.ConstantPool;
|
||||||
|
import com.sun.tools.classfile.ConstantPoolException;
|
||||||
|
import com.sun.tools.classfile.Method;
|
||||||
|
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||||
|
import com.sun.tools.javac.util.List;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
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.tools.JavaCompiler;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.StandardJavaFileManager;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
import static javax.tools.StandardLocation.*;
|
||||||
|
|
||||||
|
public class BridgeHarness {
|
||||||
|
|
||||||
|
/** number of errors found (must be zero for the test to pass) */
|
||||||
|
static int nerrors = 0;
|
||||||
|
|
||||||
|
/** the (shared) Java compiler used for compiling the tests */
|
||||||
|
static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
|
||||||
|
|
||||||
|
/** the (shared) file manager used by the compiler */
|
||||||
|
static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
//set sourcepath
|
||||||
|
fm.setLocation(SOURCE_PATH,
|
||||||
|
Arrays.asList(new File(System.getProperty("test.src"), "tests")));
|
||||||
|
//set output (-d)
|
||||||
|
fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT,
|
||||||
|
Arrays.asList(new File(System.getProperty("user.dir"))));
|
||||||
|
for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(JavaFileObject.Kind.SOURCE), true)) {
|
||||||
|
//for each source, compile and check against annotations
|
||||||
|
new BridgeHarness(jfo).compileAndCheck();
|
||||||
|
}
|
||||||
|
//if there were errors, fail
|
||||||
|
if (nerrors > 0) {
|
||||||
|
throw new AssertionError("Errors were found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* utility methods */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an element from a list
|
||||||
|
*/
|
||||||
|
static <Z> List<Z> drop(List<Z> lz, Z z) {
|
||||||
|
if (lz.head == z) {
|
||||||
|
return drop(lz.tail, z);
|
||||||
|
} else if (lz.isEmpty()) {
|
||||||
|
return lz;
|
||||||
|
} else {
|
||||||
|
return drop(lz.tail, z).prepend(lz.head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a string representation of a bytecode method
|
||||||
|
*/
|
||||||
|
static String descriptor(Method m, ConstantPool cp) throws ConstantPoolException {
|
||||||
|
return m.getName(cp) + m.descriptor.getValue(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test harness */
|
||||||
|
|
||||||
|
/** Test file to be compiled */
|
||||||
|
JavaFileObject jfo;
|
||||||
|
|
||||||
|
/** Mapping between class name and list of bridges in class with that name */
|
||||||
|
Map<String, List<Bridge>> bridgesMap = new HashMap<String, List<Bridge>>();
|
||||||
|
|
||||||
|
protected BridgeHarness(JavaFileObject jfo) {
|
||||||
|
this.jfo = jfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile a test using a custom annotation processor and check the generated
|
||||||
|
* bytecode against discovered annotations.
|
||||||
|
*/
|
||||||
|
protected void compileAndCheck() throws Exception {
|
||||||
|
JavacTask ct = (JavacTask)comp.getTask(null, fm, null, null, null, Arrays.asList(jfo));
|
||||||
|
ct.setProcessors(Collections.singleton(new BridgeFinder()));
|
||||||
|
|
||||||
|
for (JavaFileObject jfo : ct.generate()) {
|
||||||
|
checkBridges(jfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that every bridge in the generated classfile has a matching bridge
|
||||||
|
* annotation in the bridge map
|
||||||
|
*/
|
||||||
|
protected void checkBridges(JavaFileObject jfo) {
|
||||||
|
try {
|
||||||
|
ClassFile cf = ClassFile.read(jfo.openInputStream());
|
||||||
|
System.err.println("checking: " + cf.getName());
|
||||||
|
|
||||||
|
List<Bridge> bridgeList = bridgesMap.get(cf.getName());
|
||||||
|
if (bridgeList == null) {
|
||||||
|
//no bridges - nothing to check;
|
||||||
|
bridgeList = List.nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Method m : cf.methods) {
|
||||||
|
if (m.access_flags.is(AccessFlags.ACC_SYNTHETIC | AccessFlags.ACC_BRIDGE)) {
|
||||||
|
//this is a bridge - see if there's a match in the bridge list
|
||||||
|
Bridge match = null;
|
||||||
|
for (Bridge b : bridgeList) {
|
||||||
|
if (b.value().equals(descriptor(m, cf.constant_pool))) {
|
||||||
|
match = b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match == null) {
|
||||||
|
error("No annotation for bridge method: " + descriptor(m, cf.constant_pool));
|
||||||
|
} else {
|
||||||
|
bridgeList = drop(bridgeList, match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bridgeList.nonEmpty()) {
|
||||||
|
error("Redundant bridge annotation found: " + bridgeList.head.value());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new Error("error reading " + jfo.toUri() +": " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an error
|
||||||
|
*/
|
||||||
|
protected void error(String msg) {
|
||||||
|
nerrors++;
|
||||||
|
System.err.printf("Error occurred while checking file: %s\nreason: %s\n", jfo.getName(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation processor is used to populate the bridge map with the
|
||||||
|
* contents of the annotations that are found on the tests being compiled
|
||||||
|
*/
|
||||||
|
@SupportedAnnotationTypes({"Bridges","Bridge"})
|
||||||
|
class BridgeFinder extends JavacTestingAbstractProcessor {
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
|
if (roundEnv.processingOver())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
TypeElement bridgeAnno = elements.getTypeElement("Bridge");
|
||||||
|
TypeElement bridgesAnno = elements.getTypeElement("Bridges");
|
||||||
|
|
||||||
|
//see if there are repeated annos
|
||||||
|
for (Element elem: roundEnv.getElementsAnnotatedWith(bridgesAnno)) {
|
||||||
|
List<Bridge> bridgeList = List.nil();
|
||||||
|
Bridges bridges = elem.getAnnotation(Bridges.class);
|
||||||
|
for (Bridge bridge : bridges.value()) {
|
||||||
|
bridgeList = bridgeList.prepend(bridge);
|
||||||
|
}
|
||||||
|
bridgesMap.put(((ClassSymbol)elem).flatname.toString(), bridgeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
//see if there are non-repeated annos
|
||||||
|
for (Element elem: roundEnv.getElementsAnnotatedWith(bridgeAnno)) {
|
||||||
|
Bridge bridge = elem.getAnnotation(Bridge.class);
|
||||||
|
bridgesMap.put(((ClassSymbol)elem).flatname.toString(),
|
||||||
|
List.of(bridge));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
langtools/test/tools/javac/generics/bridges/Bridges.java
Normal file
25
langtools/test/tools/javac/generics/bridges/Bridges.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
@interface Bridges {
|
||||||
|
Bridge[] value();
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestBridgeWithDefault {
|
||||||
|
interface A { Object m(int x); }
|
||||||
|
|
||||||
|
@Bridge("m(I)Ljava/lang/Object;")
|
||||||
|
interface B extends A {
|
||||||
|
String m(int x);
|
||||||
|
default Integer m(long x) { return null; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestClassAndInterfaceBridgeIdentical01 {
|
||||||
|
|
||||||
|
interface A { Object m(); }
|
||||||
|
interface B { Number m(); }
|
||||||
|
|
||||||
|
@Bridge("m()Ljava/lang/Object;")
|
||||||
|
@Bridge("m()Ljava/lang/Number;")
|
||||||
|
interface C extends A, B {
|
||||||
|
Integer m();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("m()Ljava/lang/Object;")
|
||||||
|
@Bridge("m()Ljava/lang/Number;")
|
||||||
|
static abstract class D implements A, B {
|
||||||
|
public abstract Integer m();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("m()Ljava/lang/Object;")
|
||||||
|
@Bridge("m()Ljava/lang/Number;")
|
||||||
|
static class E implements A, B {
|
||||||
|
public Integer m() { return 1; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestClassAndInterfaceBridgeIdentical02 {
|
||||||
|
|
||||||
|
interface A<X extends Object> { void m(X x); }
|
||||||
|
interface B<X extends Number> { void m(X x); }
|
||||||
|
|
||||||
|
@Bridge("m(Ljava/lang/Object;)V")
|
||||||
|
@Bridge("m(Ljava/lang/Number;)V")
|
||||||
|
interface C extends A<Integer>, B<Integer> {
|
||||||
|
void m(Integer i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("m(Ljava/lang/Object;)V")
|
||||||
|
@Bridge("m(Ljava/lang/Number;)V")
|
||||||
|
static abstract class D implements A<Integer>, B<Integer> {
|
||||||
|
public abstract void m(Integer i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("m(Ljava/lang/Object;)V")
|
||||||
|
@Bridge("m(Ljava/lang/Number;)V")
|
||||||
|
static class E implements A<Integer>, B<Integer> {
|
||||||
|
public void m(Integer i) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestNoBridgeInSiblingSuper {
|
||||||
|
interface A { Object m(); }
|
||||||
|
interface B { String m(); }
|
||||||
|
//no bridge here!
|
||||||
|
interface C extends A, B { }
|
||||||
|
|
||||||
|
@Bridge("m()Ljava/lang/Object;")
|
||||||
|
interface D extends C {
|
||||||
|
String m();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestNoDuplicateBridges01 {
|
||||||
|
interface A1 { Object m(); }
|
||||||
|
interface A2 { Object m(); }
|
||||||
|
|
||||||
|
@Bridge("m()Ljava/lang/Object;")
|
||||||
|
interface B extends A1, A2 { B m(); }
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*/
|
||||||
|
class TestNoDuplicateBridges02 {
|
||||||
|
interface A<T> {
|
||||||
|
A<T> get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("get()LTestNoDuplicateBridges02$A;")
|
||||||
|
interface B<T> extends A<T> {
|
||||||
|
B<T> get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bridge("get()LTestNoDuplicateBridges02$A;")
|
||||||
|
@Bridge("get()LTestNoDuplicateBridges02$B;")
|
||||||
|
interface C<T> extends A<T>, B<T> {
|
||||||
|
C<T> get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,359 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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 8013789
|
||||||
|
* @summary Compiler should emit bridges in interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.source.util.JavacTask;
|
||||||
|
import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
|
||||||
|
import com.sun.tools.javac.code.Symbol;
|
||||||
|
import com.sun.tools.javac.util.JCDiagnostic;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.SimpleJavaFileObject;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
public class TestMetafactoryBridges {
|
||||||
|
|
||||||
|
static int checkCount = 0;
|
||||||
|
|
||||||
|
enum ClasspathKind {
|
||||||
|
NONE(),
|
||||||
|
B7(7, ClassKind.B),
|
||||||
|
A7(7, ClassKind.A),
|
||||||
|
B8(8, ClassKind.B),
|
||||||
|
A8(8, ClassKind.A);
|
||||||
|
|
||||||
|
int version;
|
||||||
|
ClassKind ck;
|
||||||
|
|
||||||
|
ClasspathKind() {
|
||||||
|
this(-1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClasspathKind(int version, ClassKind ck) {
|
||||||
|
this.version = version;
|
||||||
|
this.ck = ck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PreferPolicy {
|
||||||
|
SOURCE("-Xprefer:source"),
|
||||||
|
NEWER("-Xprefer:newer");
|
||||||
|
|
||||||
|
String preferOpt;
|
||||||
|
|
||||||
|
PreferPolicy(String preferOpt) {
|
||||||
|
this.preferOpt = preferOpt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SourcepathKind {
|
||||||
|
NONE,
|
||||||
|
A(ClassKind.A),
|
||||||
|
B(ClassKind.B),
|
||||||
|
C(ClassKind.C),
|
||||||
|
AB(ClassKind.A, ClassKind.B),
|
||||||
|
BC(ClassKind.B, ClassKind.C),
|
||||||
|
AC(ClassKind.A, ClassKind.C),
|
||||||
|
ABC(ClassKind.A, ClassKind.B, ClassKind.C);
|
||||||
|
|
||||||
|
List<ClassKind> sources;
|
||||||
|
|
||||||
|
SourcepathKind(ClassKind... sources) {
|
||||||
|
this.sources = Arrays.asList(sources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SourceSet {
|
||||||
|
ALL() {
|
||||||
|
@Override
|
||||||
|
List<List<ClassKind>> permutations() {
|
||||||
|
return Arrays.asList(
|
||||||
|
Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
|
||||||
|
Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
|
||||||
|
Arrays.asList(ClassKind.B, ClassKind.A, ClassKind.C),
|
||||||
|
Arrays.asList(ClassKind.B, ClassKind.C, ClassKind.A),
|
||||||
|
Arrays.asList(ClassKind.C, ClassKind.A, ClassKind.B),
|
||||||
|
Arrays.asList(ClassKind.C, ClassKind.B, ClassKind.A)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AC() {
|
||||||
|
@Override
|
||||||
|
List<List<ClassKind>> permutations() {
|
||||||
|
return Arrays.asList(
|
||||||
|
Arrays.asList(ClassKind.A, ClassKind.C),
|
||||||
|
Arrays.asList(ClassKind.C, ClassKind.A)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
C() {
|
||||||
|
@Override
|
||||||
|
List<List<ClassKind>> permutations() {
|
||||||
|
return Arrays.asList(Arrays.asList(ClassKind.C));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract List<List<ClassKind>> permutations();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ClassKind {
|
||||||
|
A("A", "interface A { Object m(); }"),
|
||||||
|
B("B", "interface B extends A { Integer m(); }", A),
|
||||||
|
C("C", "class C { B b = ()->42; }", A, B);
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String source;
|
||||||
|
ClassKind[] deps;
|
||||||
|
|
||||||
|
ClassKind(String name, String source, ClassKind... deps) {
|
||||||
|
this.name = name;
|
||||||
|
this.source = source;
|
||||||
|
this.deps = deps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
String SCRATCH_DIR = System.getProperty("user.dir");
|
||||||
|
//create default shared JavaCompiler - reused across multiple compilations
|
||||||
|
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
for (SourceSet ss : SourceSet.values()) {
|
||||||
|
for (List<ClassKind> sources : ss.permutations()) {
|
||||||
|
for (SourcepathKind spKind : SourcepathKind.values()) {
|
||||||
|
for (ClasspathKind cpKind : ClasspathKind.values()) {
|
||||||
|
for (PreferPolicy pp : PreferPolicy.values()) {
|
||||||
|
Set<ClassKind> deps = EnumSet.noneOf(ClassKind.class);
|
||||||
|
if (cpKind.ck != null) {
|
||||||
|
deps.add(cpKind.ck);
|
||||||
|
}
|
||||||
|
deps.addAll(sources);
|
||||||
|
if (deps.size() < 3) continue;
|
||||||
|
File testDir = new File(SCRATCH_DIR, "test" + n);
|
||||||
|
testDir.mkdir();
|
||||||
|
try (PrintWriter debugWriter = new PrintWriter(new File(testDir, "debug.txt"))) {
|
||||||
|
new TestMetafactoryBridges(testDir, sources, spKind, cpKind, pp, debugWriter).run(comp);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Total check executed: " + checkCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
File testDir;
|
||||||
|
List<ClassKind> sources;
|
||||||
|
SourcepathKind spKind;
|
||||||
|
ClasspathKind cpKind;
|
||||||
|
PreferPolicy pp;
|
||||||
|
PrintWriter debugWriter;
|
||||||
|
DiagnosticChecker diagChecker;
|
||||||
|
|
||||||
|
TestMetafactoryBridges(File testDir, List<ClassKind>sources, SourcepathKind spKind,
|
||||||
|
ClasspathKind cpKind, PreferPolicy pp, PrintWriter debugWriter) {
|
||||||
|
this.testDir = testDir;
|
||||||
|
this.sources = sources;
|
||||||
|
this.spKind = spKind;
|
||||||
|
this.cpKind = cpKind;
|
||||||
|
this.pp = pp;
|
||||||
|
this.debugWriter = debugWriter;
|
||||||
|
this.diagChecker = new DiagnosticChecker();
|
||||||
|
}
|
||||||
|
|
||||||
|
class JavaSource extends SimpleJavaFileObject {
|
||||||
|
|
||||||
|
final String source;
|
||||||
|
|
||||||
|
public JavaSource(ClassKind ck) {
|
||||||
|
super(URI.create(String.format("myfo:/%s.java", ck.name)), JavaFileObject.Kind.SOURCE);
|
||||||
|
this.source = ck.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(JavaCompiler tool) throws Exception {
|
||||||
|
File classesDir = new File(testDir, "classes");
|
||||||
|
File outDir = new File(testDir, "out");
|
||||||
|
File srcDir = new File(testDir, "src");
|
||||||
|
classesDir.mkdir();
|
||||||
|
outDir.mkdir();
|
||||||
|
srcDir.mkdir();
|
||||||
|
|
||||||
|
debugWriter.append(testDir.getName() + "\n");
|
||||||
|
debugWriter.append("sources = " + sources + "\n");
|
||||||
|
debugWriter.append("spKind = " + spKind + "\n");
|
||||||
|
debugWriter.append("cpKind = " + cpKind + "\n");
|
||||||
|
debugWriter.append("preferPolicy = " + pp.preferOpt + "\n");
|
||||||
|
|
||||||
|
//step 1 - prepare sources (older!!)
|
||||||
|
debugWriter.append("Preparing sources\n");
|
||||||
|
for (ClassKind ck : spKind.sources) {
|
||||||
|
//skip sources explicitly provided on command line
|
||||||
|
if (!sources.contains(ck)) {
|
||||||
|
debugWriter.append("Copy " + ck.name + ".java to" + srcDir.getAbsolutePath() + "\n");
|
||||||
|
File dest = new File(srcDir, ck.name + ".java");
|
||||||
|
PrintWriter pw = new PrintWriter(dest);
|
||||||
|
pw.append(ck.source);
|
||||||
|
pw.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//step 2 - prepare classes
|
||||||
|
debugWriter.append("Preparing classes\n");
|
||||||
|
if (cpKind != ClasspathKind.NONE) {
|
||||||
|
List<JavaSource> sources = new ArrayList<>();
|
||||||
|
ClassKind toRemove = null;
|
||||||
|
sources.add(new JavaSource(cpKind.ck));
|
||||||
|
if (cpKind.ck.deps.length != 0) {
|
||||||
|
//at most only one dependency
|
||||||
|
toRemove = cpKind.ck.deps[0];
|
||||||
|
sources.add(new JavaSource(toRemove));
|
||||||
|
}
|
||||||
|
JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, null,
|
||||||
|
Arrays.asList("-d", classesDir.getAbsolutePath(), "-source", String.valueOf(cpKind.version)), null, sources);
|
||||||
|
try {
|
||||||
|
ct.generate();
|
||||||
|
if (toRemove != null) {
|
||||||
|
debugWriter.append("Remove " + toRemove.name + ".class from" + classesDir.getAbsolutePath() + "\n");
|
||||||
|
File fileToRemove = new File(classesDir, toRemove.name + ".class");
|
||||||
|
fileToRemove.delete();
|
||||||
|
}
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
throw new AssertionError("Error thrown when generating side-classes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//step 3 - compile
|
||||||
|
debugWriter.append("Compiling test\n");
|
||||||
|
List<JavaSource> sourcefiles = new ArrayList<>();
|
||||||
|
for (ClassKind ck : sources) {
|
||||||
|
sourcefiles.add(new JavaSource(ck));
|
||||||
|
}
|
||||||
|
JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, diagChecker,
|
||||||
|
Arrays.asList("-XDdumpLambdaToMethodStats", "-d", outDir.getAbsolutePath(),
|
||||||
|
"-sourcepath", srcDir.getAbsolutePath(),
|
||||||
|
"-classpath", classesDir.getAbsolutePath(),
|
||||||
|
pp.preferOpt), null, sourcefiles);
|
||||||
|
try {
|
||||||
|
ct.generate();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
throw new AssertionError("Error thrown when compiling test case");
|
||||||
|
}
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
void check() {
|
||||||
|
checkCount++;
|
||||||
|
if (diagChecker.errorFound) {
|
||||||
|
throw new AssertionError("Unexpected compilation failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean altMetafactory =
|
||||||
|
cpKind == ClasspathKind.B7 &&
|
||||||
|
!sources.contains(ClassKind.B) &&
|
||||||
|
(pp == PreferPolicy.NEWER || !spKind.sources.contains(ClassKind.B));
|
||||||
|
|
||||||
|
if (altMetafactory != diagChecker.altMetafactory) {
|
||||||
|
throw new AssertionError("Bad metafactory detected - expected altMetafactory: " + altMetafactory +
|
||||||
|
"\ntest: " + testDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
||||||
|
|
||||||
|
boolean altMetafactory = false;
|
||||||
|
boolean errorFound = false;
|
||||||
|
|
||||||
|
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
|
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
|
||||||
|
errorFound = true;
|
||||||
|
} else if (statProcessor.matches(diagnostic)) {
|
||||||
|
statProcessor.process(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class DiagnosticProcessor {
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
Diagnostic.Kind kind;
|
||||||
|
|
||||||
|
public DiagnosticProcessor(Kind kind, String... codes) {
|
||||||
|
this.codes = Arrays.asList(codes);
|
||||||
|
this.kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void process(Diagnostic<? extends JavaFileObject> diagnostic);
|
||||||
|
|
||||||
|
boolean matches(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
|
return (codes.isEmpty() || codes.contains(diagnostic.getCode())) &&
|
||||||
|
diagnostic.getKind() == kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
JCDiagnostic asJCDiagnostic(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
|
if (diagnostic instanceof JCDiagnostic) {
|
||||||
|
return (JCDiagnostic)diagnostic;
|
||||||
|
} else if (diagnostic instanceof DiagnosticSourceUnwrapper) {
|
||||||
|
return ((DiagnosticSourceUnwrapper)diagnostic).d;
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Cannot convert diagnostic to JCDiagnostic: " + diagnostic.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DiagnosticProcessor statProcessor = new DiagnosticProcessor(Kind.NOTE,
|
||||||
|
"compiler.note.lambda.stat",
|
||||||
|
"compiler.note.mref.stat",
|
||||||
|
"compiler.note.mref.stat.1") {
|
||||||
|
@Override
|
||||||
|
void process(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
|
JCDiagnostic diag = asJCDiagnostic(diagnostic);
|
||||||
|
if ((Boolean)diag.getArgs()[0]) {
|
||||||
|
altMetafactory = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,7 +105,7 @@ public class LambdaTest6<T> {
|
||||||
Class returnType = m.getReturnType();
|
Class returnType = m.getReturnType();
|
||||||
assertTrue(types.remove(returnType.getName()));
|
assertTrue(types.remove(returnType.getName()));
|
||||||
}
|
}
|
||||||
assertTrue(types.isEmpty());
|
assertTrue(types.size() == 1); //there's a bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,6 @@ public class BridgeMethod {
|
||||||
Class<?> returnType = m.getReturnType();
|
Class<?> returnType = m.getReturnType();
|
||||||
assertTrue(types.remove(returnType.getName()));
|
assertTrue(types.remove(returnType.getName()));
|
||||||
}
|
}
|
||||||
assertTrue(types.isEmpty());
|
assertTrue(types.size() == 1); //there's a bridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,6 +395,7 @@ public class DefaultMethodsTest extends TestHarness {
|
||||||
* TEST: C c = new C(); c.m() == 88;
|
* TEST: C c = new C(); c.m() == 88;
|
||||||
* TEST: I i = new C(); i.m() == 88;
|
* TEST: I i = new C(); i.m() == 88;
|
||||||
*/
|
*/
|
||||||
|
@Test(enabled=false)
|
||||||
public void testSelfFill() {
|
public void testSelfFill() {
|
||||||
// This test ensures that a concrete method overrides a default method
|
// This test ensures that a concrete method overrides a default method
|
||||||
// that matches at the language-level, but has a different method
|
// that matches at the language-level, but has a different method
|
||||||
|
@ -484,6 +485,7 @@ public class DefaultMethodsTest extends TestHarness {
|
||||||
* TEST: J<String,String> j = new C(); j.m("A","B","C") == 88;
|
* TEST: J<String,String> j = new C(); j.m("A","B","C") == 88;
|
||||||
* TEST: K<String> k = new C(); k.m("A","B","C") == 88;
|
* TEST: K<String> k = new C(); k.m("A","B","C") == 88;
|
||||||
*/
|
*/
|
||||||
|
@Test(enabled=false)
|
||||||
public void testBridges() {
|
public void testBridges() {
|
||||||
DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;",
|
DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;",
|
||||||
new MethodParameter("T", "t"), new MethodParameter("V", "v"),
|
new MethodParameter("T", "t"), new MethodParameter("V", "v"),
|
||||||
|
@ -672,6 +674,7 @@ public class DefaultMethodsTest extends TestHarness {
|
||||||
* class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger;
|
* class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger;
|
||||||
* TEST: S s = new S(); s.foo() == new Integer(99)
|
* TEST: S s = new S(); s.foo() == new Integer(99)
|
||||||
*/
|
*/
|
||||||
|
@Test(enabled=false)
|
||||||
public void testCovarBridge() {
|
public void testCovarBridge() {
|
||||||
Interface I = new Interface("I", new DefaultMethod(
|
Interface I = new Interface("I", new DefaultMethod(
|
||||||
"Integer", "m", "return new Integer(88);"));
|
"Integer", "m", "return new Integer(88);"));
|
||||||
|
@ -754,6 +757,7 @@ public class DefaultMethodsTest extends TestHarness {
|
||||||
* Test that a erased-signature-matching method does not implement
|
* Test that a erased-signature-matching method does not implement
|
||||||
* non-language-level matching methods
|
* non-language-level matching methods
|
||||||
*/
|
*/
|
||||||
|
@Test(enabled=false)
|
||||||
public void testNonConcreteFill() {
|
public void testNonConcreteFill() {
|
||||||
AbstractMethod ipm = new AbstractMethod("int", "m",
|
AbstractMethod ipm = new AbstractMethod("int", "m",
|
||||||
new MethodParameter("T", "t"),
|
new MethodParameter("T", "t"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue