提交 924002c6 编写于 作者: M mcimadamore

8005244: Implement overload resolution as per latest spec EDR

Summary: Add support for stuck expressions and provisional applicability
Reviewed-by: jjg
上级 b047fa02
......@@ -218,6 +218,12 @@ public enum Source {
public boolean allowIntersectionTypesInCast() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowEarlyReturnConstraints() {
return compareTo(JDK1_8) >= 0;
}
public boolean allowStructuralMostSpecific() {
return compareTo(JDK1_8) >= 0;
}
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:
......
......@@ -354,8 +354,29 @@ public class Types {
return descSym;
}
public Type getType(Type origin) {
return memberType(origin, descSym);
public Type getType(Type site) {
if (capture(site) != site) {
Type formalInterface = site.tsym.type;
ListBuffer<Type> typeargs = ListBuffer.lb();
List<Type> actualTypeargs = site.getTypeArguments();
//simply replace the wildcards with its bound
for (Type t : formalInterface.getTypeArguments()) {
if (actualTypeargs.head.hasTag(WILDCARD)) {
WildcardType wt = (WildcardType)actualTypeargs.head;
typeargs.append(wt.type);
} else {
typeargs.append(actualTypeargs.head);
}
actualTypeargs = actualTypeargs.tail;
}
site = subst(formalInterface, formalInterface.getTypeArguments(), typeargs.toList());
if (!chk.checkValidGenericType(site)) {
//if the inferred functional interface type is not well-formed,
//or if it's not a subtype of the original target, issue an error
throw failure(diags.fragment("no.suitable.functional.intf.inst", site));
}
}
return memberType(site, descSym);
}
}
......@@ -553,6 +574,15 @@ public class Types {
return false;
}
}
public boolean isFunctionalInterface(Type site) {
try {
findDescriptorType(site);
return true;
} catch (FunctionDescriptorLookupError ex) {
return false;
}
}
// </editor-fold>
/**
......
......@@ -48,6 +48,7 @@ import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
......@@ -1376,18 +1377,19 @@ public class Attr extends JCTree.Visitor {
public void visitConditional(JCConditional tree) {
Type condtype = attribExpr(tree.cond, env, syms.booleanType);
boolean standaloneConditional = !allowPoly ||
tree.polyKind = (!allowPoly ||
pt().hasTag(NONE) && pt() != Type.recoveryType ||
isBooleanOrNumeric(env, tree);
isBooleanOrNumeric(env, tree)) ?
PolyKind.STANDALONE : PolyKind.POLY;
if (!standaloneConditional && resultInfo.pt.hasTag(VOID)) {
if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
//cannot get here (i.e. it means we are returning from void method - which is already an error)
resultInfo.checkContext.report(tree, diags.fragment("conditional.target.cant.be.void"));
result = tree.type = types.createErrorType(resultInfo.pt);
return;
}
ResultInfo condInfo = standaloneConditional ?
ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
unknownExprInfo :
resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
//this will use enclosing check context to check compatibility of
......@@ -1402,7 +1404,7 @@ public class Attr extends JCTree.Visitor {
Type truetype = attribTree(tree.truepart, env, condInfo);
Type falsetype = attribTree(tree.falsepart, env, condInfo);
Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt();
Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, truetype, falsetype) : pt();
if (condtype.constValue() != null &&
truetype.constValue() != null &&
falsetype.constValue() != null &&
......@@ -1424,12 +1426,30 @@ public class Attr extends JCTree.Visitor {
JCConditional condTree = (JCConditional)tree;
return isBooleanOrNumeric(env, condTree.truepart) &&
isBooleanOrNumeric(env, condTree.falsepart);
case APPLY:
JCMethodInvocation speculativeMethodTree =
(JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo);
Type owntype = TreeInfo.symbol(speculativeMethodTree.meth).type.getReturnType();
return types.unboxedTypeOrType(owntype).isPrimitive();
case NEWCLASS:
JCExpression className =
removeClassParams.translate(((JCNewClass)tree).clazz);
JCExpression speculativeNewClassTree =
(JCExpression)deferredAttr.attribSpeculative(className, env, unknownTypeInfo);
return types.unboxedTypeOrType(speculativeNewClassTree.type).isPrimitive();
default:
Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type;
speculativeType = types.unboxedTypeOrType(speculativeType);
return speculativeType.isPrimitive();
}
}
//where
TreeTranslator removeClassParams = new TreeTranslator() {
@Override
public void visitTypeApply(JCTypeApply tree) {
result = translate(tree.clazz);
}
};
/** Compute the type of a conditional expression, after
* checking that it exists. See JLS 15.25. Does not take into
......@@ -2173,17 +2193,18 @@ public class Attr extends JCTree.Visitor {
boolean needsRecovery =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
try {
Type target = pt();
List<Type> explicitParamTypes = null;
if (TreeInfo.isExplicitLambda(that)) {
if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
//attribute lambda parameters
attribStats(that.params, localEnv);
explicitParamTypes = TreeInfo.types(that.params);
target = infer.instantiateFunctionalInterface(that, target, explicitParamTypes, resultInfo.checkContext);
}
Type target;
Type lambdaType;
if (pt() != Type.recoveryType) {
target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), explicitParamTypes, resultInfo.checkContext);
target = checkIntersectionTarget(that, target, resultInfo.checkContext);
lambdaType = types.findDescriptorType(target);
chk.checkFunctionalInterface(that, target);
} else {
......@@ -2191,6 +2212,8 @@ public class Attr extends JCTree.Visitor {
lambdaType = fallbackDescriptorType(that);
}
setFunctionalInfo(that, pt(), lambdaType, resultInfo.checkContext.inferenceContext());
if (lambdaType.hasTag(FORALL)) {
//lambda expression target desc cannot be a generic method
resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
......@@ -2199,7 +2222,7 @@ public class Attr extends JCTree.Visitor {
return;
}
if (!TreeInfo.isExplicitLambda(that)) {
if (that.paramKind == JCLambda.ParameterKind.IMPLICIT) {
//add param type info in the AST
List<Type> actuals = lambdaType.getParameterTypes();
List<JCVariableDecl> params = that.params;
......@@ -2282,8 +2305,7 @@ public class Attr extends JCTree.Visitor {
}
}
private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) {
Type pt = resultInfo.pt;
private Type checkIntersectionTarget(DiagnosticPosition pos, Type pt, CheckContext checkContext) {
if (pt != Type.recoveryType && pt.isCompound()) {
IntersectionClassType ict = (IntersectionClassType)pt;
List<Type> bounds = ict.allInterfaces ?
......@@ -2292,7 +2314,7 @@ public class Attr extends JCTree.Visitor {
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));
checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound));
}
}
//for now (translation doesn't support intersection types)
......@@ -2355,9 +2377,9 @@ public class Attr extends JCTree.Visitor {
@Override
public boolean compatible(Type found, Type req, Warner warn) {
//return type must be compatible in both current context and assignment context
return types.isAssignable(found, inferenceContext().asFree(req, types), warn) &&
super.compatible(found, req, warn);
return chk.basicHandler.compatible(found, inferenceContext().asFree(req, types), warn);
}
@Override
public void report(DiagnosticPosition pos, JCDiagnostic details) {
enclosingContext.report(pos, diags.fragment("incompatible.ret.type.in.lambda", details));
......@@ -2473,7 +2495,7 @@ public class Attr extends JCTree.Visitor {
Type target;
Type desc;
if (pt() != Type.recoveryType) {
target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), null, resultInfo.checkContext);
target = checkIntersectionTarget(that, pt(), resultInfo.checkContext);
desc = types.findDescriptorType(target);
chk.checkFunctionalInterface(that, target);
} else {
......@@ -2481,12 +2503,11 @@ public class Attr extends JCTree.Visitor {
desc = fallbackDescriptorType(that);
}
setFunctionalInfo(that, pt(), desc, resultInfo.checkContext.inferenceContext());
List<Type> argtypes = desc.getParameterTypes();
boolean allowBoxing =
resultInfo.checkContext.deferredAttrContext().phase.isBoxingRequired();
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult = rs.resolveMemberReference(that.pos(), localEnv, that,
that.expr.type, that.name, argtypes, typeargtypes, allowBoxing);
that.expr.type, that.name, argtypes, typeargtypes, true);
Symbol refSym = refResult.fst;
Resolve.ReferenceLookupHelper lookupHelper = refResult.snd;
......@@ -2635,6 +2656,34 @@ public class Attr extends JCTree.Visitor {
}
}
/**
* Set functional type info on the underlying AST. Note: as the target descriptor
* might contain inference variables, we might need to register an hook in the
* current inference context.
*/
private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt, final Type descriptorType, InferenceContext inferenceContext) {
if (inferenceContext.free(descriptorType)) {
inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
public void typesInferred(InferenceContext inferenceContext) {
setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType, types), inferenceContext);
}
});
} else {
ListBuffer<TypeSymbol> targets = ListBuffer.lb();
if (pt.hasTag(CLASS)) {
if (pt.isCompound()) {
for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
targets.append(t.tsym);
}
} else {
targets.append(pt.tsym);
}
}
fExpr.targets = targets.toList();
fExpr.descriptorType = descriptorType;
}
}
public void visitParens(JCParens tree) {
Type owntype = attribTree(tree.expr, env, resultInfo);
result = check(tree, owntype, pkind(), resultInfo);
......@@ -4077,12 +4126,29 @@ public class Attr extends JCTree.Visitor {
super.visitUnary(that);
}
@Override
public void visitLambda(JCLambda that) {
super.visitLambda(that);
if (that.descriptorType == null) {
that.descriptorType = syms.unknownType;
}
if (that.targets == null) {
that.targets = List.nil();
}
}
@Override
public void visitReference(JCMemberReference that) {
super.visitReference(that);
if (that.sym == null) {
that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol);
}
if (that.descriptorType == null) {
that.descriptorType = syms.unknownType;
}
if (that.targets == null) {
that.targets = List.nil();
}
}
}
// </editor-fold>
......
......@@ -36,7 +36,6 @@ import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Type.*;
......@@ -44,6 +43,8 @@ import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Flags.ANNOTATION;
......@@ -900,7 +901,6 @@ public class Check {
syms.methodClass);
}
if (useVarargs) {
JCTree tree = env.tree;
Type argtype = owntype.getParameterTypes().last();
if (!types.isReifiable(argtype) &&
(!allowSimplifiedVarargs ||
......@@ -911,22 +911,13 @@ public class Check {
argtype);
}
if (!((MethodSymbol)sym.baseSymbol()).isSignaturePolymorphic(types)) {
Type elemtype = types.elemtype(argtype);
switch (tree.getTag()) {
case APPLY:
((JCMethodInvocation) tree).varargsElement = elemtype;
break;
case NEWCLASS:
((JCNewClass) tree).varargsElement = elemtype;
break;
case REFERENCE:
((JCMemberReference) tree).varargsElement = elemtype;
break;
default:
throw new AssertionError(""+tree);
}
TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype));
}
}
PolyKind pkind = (sym.type.hasTag(FORALL) &&
sym.type.getReturnType().containsAny(((ForAll)sym.type).tvars)) ?
PolyKind.POLY : PolyKind.STANDALONE;
TreeInfo.setPolyKind(env.tree, pkind);
return owntype;
}
//where
......
......@@ -65,6 +65,7 @@ public class DeferredAttr extends JCTree.Visitor {
final Attr attr;
final Check chk;
final JCDiagnostic.Factory diags;
final Enter enter;
final Infer infer;
final Log log;
......@@ -83,14 +84,20 @@ public class DeferredAttr extends JCTree.Visitor {
context.put(deferredAttrKey, this);
attr = Attr.instance(context);
chk = Check.instance(context);
diags = JCDiagnostic.Factory.instance(context);
enter = Enter.instance(context);
infer = Infer.instance(context);
log = Log.instance(context);
syms = Symtab.instance(context);
make = TreeMaker.instance(context);
types = Types.instance(context);
Names names = Names.instance(context);
stuckTree = make.Ident(names.empty).setType(Type.noType);
}
/** shared tree for stuck expressions */
final JCTree stuckTree;
/**
* This type represents a deferred type. A deferred type starts off with
* no information on the underlying expression type. Such info needs to be
......@@ -356,12 +363,11 @@ public class DeferredAttr extends JCTree.Visitor {
//scan a defensive copy of the node list - this is because a deferred
//attribution round can add new nodes to the list
for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
if (!deferredAttrNode.isStuck()) {
deferredAttrNode.process();
if (!deferredAttrNode.process()) {
stuckVars.addAll(deferredAttrNode.stuckVars);
} else {
deferredAttrNodes.remove(deferredAttrNode);
progress = true;
} else {
stuckVars.addAll(deferredAttrNode.stuckVars);
}
}
if (!progress) {
......@@ -404,21 +410,88 @@ public class DeferredAttr extends JCTree.Visitor {
}
/**
* is this node stuck?
* Process a deferred attribution node.
* Invariant: a stuck node cannot be processed.
*/
boolean isStuck() {
return stuckVars.nonEmpty();
@SuppressWarnings("fallthrough")
boolean process() {
switch (mode) {
case SPECULATIVE:
dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker());
return true;
case CHECK:
if (stuckVars.nonEmpty()) {
return false;
} else {
dt.check(resultInfo, stuckVars, basicCompleter);
return true;
}
default:
throw new AssertionError("Bad mode");
}
}
/**
* Process a deferred attribution node.
* Invariant: a stuck node cannot be processed.
* Structural checker for stuck expressions
*/
void process() {
if (isStuck()) {
throw new IllegalStateException("Cannot process a stuck deferred node");
class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
ResultInfo resultInfo;
public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
this.resultInfo = resultInfo;
dt.tree.accept(this);
dt.speculativeCache.put(msym, stuckTree, phase);
return Type.noType;
}
@Override
public void visitLambda(JCLambda tree) {
Check.CheckContext checkContext = resultInfo.checkContext;
Type pt = resultInfo.pt;
if (inferenceContext.inferencevars.contains(pt)) {
//ok
return;
} else {
//must be a functional descriptor
try {
Type desc = types.findDescriptorType(pt);
if (desc.getParameterTypes().length() != tree.params.length()) {
checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
}
} catch (Types.FunctionDescriptorLookupError ex) {
checkContext.report(null, ex.getDiagnostic());
}
}
}
@Override
public void visitNewClass(JCNewClass tree) {
//do nothing
}
@Override
public void visitApply(JCMethodInvocation tree) {
//do nothing
}
@Override
public void visitReference(JCMemberReference tree) {
Check.CheckContext checkContext = resultInfo.checkContext;
Type pt = resultInfo.pt;
if (inferenceContext.inferencevars.contains(pt)) {
//ok
return;
} else {
try {
//TODO: we should speculative determine if there's a match
//based on arity - if yes, method is applicable.
types.findDescriptorType(pt);
} catch (Types.FunctionDescriptorLookupError ex) {
checkContext.report(null, ex.getDiagnostic());
}
}
}
dt.check(resultInfo);
}
}
}
......@@ -624,12 +697,12 @@ public class DeferredAttr extends JCTree.Visitor {
if (inferenceContext.inferenceVars().contains(pt)) {
stuckVars.add(pt);
}
if (!types.isFunctionalInterface(pt.tsym)) {
if (!types.isFunctionalInterface(pt)) {
return;
}
Type descType = types.findDescriptorType(pt);
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
if (!TreeInfo.isExplicitLambda(tree) &&
if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
freeArgVars.nonEmpty()) {
stuckVars.addAll(freeArgVars);
}
......@@ -643,7 +716,7 @@ public class DeferredAttr extends JCTree.Visitor {
stuckVars.add(pt);
return;
}
if (!types.isFunctionalInterface(pt.tsym)) {
if (!types.isFunctionalInterface(pt)) {
return;
}
......
......@@ -66,6 +66,9 @@ public class Infer {
Log log;
JCDiagnostic.Factory diags;
/** Should we inject return-type constraints earlier? */
boolean allowEarlyReturnConstraints;
public static Infer instance(Context context) {
Infer instance = context.get(inferKey);
if (instance == null)
......@@ -83,6 +86,7 @@ public class Infer {
chk = Check.instance(context);
diags = JCDiagnostic.Factory.instance(context);
inferenceException = new InferenceException(diags);
allowEarlyReturnConstraints = Source.instance(context).allowEarlyReturnConstraints();
}
/**
......@@ -188,19 +192,6 @@ public class Infer {
MethodType mtype,
Attr.ResultInfo resultInfo,
Warner warn) throws InferenceException {
Type to = resultInfo.pt;
if (to.hasTag(NONE) || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
to = mtype.getReturnType().isPrimitiveOrVoid() ?
mtype.getReturnType() : syms.objectType;
}
Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
if (!types.isSubtype(qtype1,
qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to)) {
throw inferenceException
.setMessage("infer.no.conforming.instance.exists",
inferenceContext.restvars(), mtype.getReturnType(), to);
}
while (true) {
boolean stuck = true;
for (Type t : inferenceContext.undetvars) {
......@@ -283,6 +274,11 @@ public class Infer {
try {
methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn);
if (resultInfo != null && allowEarlyReturnConstraints &&
!warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
generateReturnConstraints(mt, inferenceContext, resultInfo);
}
deferredAttrContext.complete();
// minimize as yet undetermined type variables
......@@ -298,6 +294,9 @@ public class Infer {
if (!restvars.isEmpty()) {
if (resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
if (!allowEarlyReturnConstraints) {
generateReturnConstraints(mt, inferenceContext, resultInfo);
}
instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
checkWithinBounds(inferenceContext, warn);
mt = (MethodType)inferenceContext.asInstType(mt, types);
......@@ -313,6 +312,23 @@ public class Infer {
inferenceContext.notifyChange(types);
}
}
//where
void generateReturnConstraints(Type mt, InferenceContext inferenceContext, Attr.ResultInfo resultInfo) {
if (resultInfo != null) {
Type to = resultInfo.pt;
if (to.hasTag(NONE) || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
to = mt.getReturnType().isPrimitiveOrVoid() ?
mt.getReturnType() : syms.objectType;
}
Type qtype1 = inferenceContext.asFree(mt.getReturnType(), types);
if (!types.isSubtype(qtype1,
qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to)) {
throw inferenceException
.setMessage("infer.no.conforming.instance.exists",
inferenceContext.restvars(), mt.getReturnType(), to);
}
}
}
/** check that type parameters are within their bounds.
*/
......@@ -461,52 +477,40 @@ public class Infer {
Type formalInterface = funcInterface.tsym.type;
InferenceContext funcInterfaceContext =
new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
if (paramTypes != null) {
//get constraints from explicit params (this is done by
//checking that explicit param types are equal to the ones
//in the functional interface descriptors)
List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
if (descParameterTypes.size() != paramTypes.size()) {
checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
Assert.check(paramTypes != null);
//get constraints from explicit params (this is done by
//checking that explicit param types are equal to the ones
//in the functional interface descriptors)
List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
if (descParameterTypes.size() != paramTypes.size()) {
checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
return types.createErrorType(funcInterface);
}
for (Type p : descParameterTypes) {
if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
return types.createErrorType(funcInterface);
}
for (Type p : descParameterTypes) {
if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
return types.createErrorType(funcInterface);
}
paramTypes = paramTypes.tail;
}
for (Type t : funcInterfaceContext.undetvars) {
UndetVar uv = (UndetVar)t;
minimizeInst(uv, types.noWarnings);
if (uv.inst == null &&
Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
maximizeInst(uv, types.noWarnings);
}
}
formalInterface = funcInterfaceContext.asInstType(formalInterface, types);
paramTypes = paramTypes.tail;
}
ListBuffer<Type> typeargs = ListBuffer.lb();
List<Type> actualTypeargs = funcInterface.getTypeArguments();
//for remaining uninferred type-vars in the functional interface type,
//simply replace the wildcards with its bound
for (Type t : formalInterface.getTypeArguments()) {
if (actualTypeargs.head.hasTag(WILDCARD)) {
WildcardType wt = (WildcardType)actualTypeargs.head;
typeargs.append(wt.type);
} else {
typeargs.append(actualTypeargs.head);
for (Type t : funcInterfaceContext.undetvars) {
UndetVar uv = (UndetVar)t;
minimizeInst(uv, types.noWarnings);
if (uv.inst == null &&
Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
maximizeInst(uv, types.noWarnings);
}
if (uv.inst == null) {
uv.inst = actualTypeargs.head;
}
actualTypeargs = actualTypeargs.tail;
}
Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList());
Type owntype = funcInterfaceContext.asInstType(formalInterface, types);
if (!chk.checkValidGenericType(owntype)) {
//if the inferred functional interface type is not well-formed,
//or if it's not a subtype of the original target, issue an error
checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
return types.createErrorType(funcInterface);
}
return owntype;
}
......
......@@ -253,7 +253,7 @@ public class LambdaToMethod extends TreeTranslator {
int refKind = referenceKind(sym);
//convert to an invokedynamic call
result = makeMetaFactoryIndyCall(tree, tree.targetType, refKind, sym, indy_args);
result = makeMetaFactoryIndyCall(tree, refKind, sym, indy_args);
}
private JCIdent makeThis(Type type, Symbol owner) {
......@@ -314,7 +314,7 @@ 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);
result = makeMetaFactoryIndyCall(tree, localContext.referenceKind(), refSym, indy_args);
}
/**
......@@ -503,19 +503,6 @@ public class LambdaToMethod extends TreeTranslator {
// </editor-fold>
private MethodSymbol makeSamDescriptor(Type targetType) {
return (MethodSymbol)types.findDescriptorSymbol(targetType.tsym);
}
private Type makeFunctionalDescriptorType(Type targetType, MethodSymbol samDescriptor, boolean erased) {
Type descType = types.memberType(targetType, samDescriptor);
return erased ? types.erasure(descType) : descType;
}
private Type makeFunctionalDescriptorType(Type targetType, boolean erased) {
return makeFunctionalDescriptorType(targetType, makeSamDescriptor(targetType), erased);
}
/**
* Generate an adapter method "bridge" for a method reference which cannot
* be used directly.
......@@ -698,12 +685,12 @@ public class LambdaToMethod extends TreeTranslator {
/**
* Generate an indy method call to the meta factory
*/
private JCExpression makeMetaFactoryIndyCall(JCExpression tree, Type targetType, int refKind, Symbol refSym, List<JCExpression> indy_args) {
private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, int refKind, Symbol refSym, List<JCExpression> indy_args) {
//determine the static bsm args
Type mtype = makeFunctionalDescriptorType(targetType, true);
Type mtype = types.erasure(tree.descriptorType);
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
List<Object> staticArgs = List.<Object>of(
new Pool.MethodHandle(ClassFile.REF_invokeInterface,
types.findDescriptorSymbol(targetType.tsym), types),
new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(tree.type.tsym), types),
new Pool.MethodHandle(refKind, refSym, types),
new MethodType(mtype.getParameterTypes(),
mtype.getReturnType(),
......@@ -1165,7 +1152,7 @@ public class LambdaToMethod extends TreeTranslator {
* This class is used to store important information regarding translation of
* lambda expression/method references (see subclasses).
*/
private abstract class TranslationContext<T extends JCTree> {
private abstract class TranslationContext<T extends JCFunctionalExpression> {
/** the underlying (untranslated) tree */
T tree;
......@@ -1329,7 +1316,7 @@ public class LambdaToMethod extends TreeTranslator {
}
Type generatedLambdaSig() {
return types.erasure(types.findDescriptorType(tree.targetType));
return types.erasure(tree.descriptorType);
}
}
......@@ -1385,7 +1372,7 @@ public class LambdaToMethod extends TreeTranslator {
}
Type bridgedRefSig() {
return types.erasure(types.findDescriptorSymbol(tree.targetType.tsym).type);
return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
}
}
}
......
......@@ -41,6 +41,7 @@ import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
......@@ -92,6 +93,7 @@ public class Resolve {
public final boolean varargsEnabled; // = source.allowVarargs();
public final boolean allowMethodHandles;
public final boolean allowDefaultMethods;
public final boolean allowStructuralMostSpecific;
private final boolean debugResolve;
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
......@@ -127,6 +129,7 @@ public class Resolve {
Target target = Target.instance(context);
allowMethodHandles = target.hasMethodHandles();
allowDefaultMethods = source.allowDefaultMethods();
allowStructuralMostSpecific = source.allowStructuralMostSpecific();
polymorphicSignatureScope = new Scope(syms.noSymbol);
inapplicableMethodException = new InapplicableMethodException(diags);
......@@ -835,6 +838,213 @@ public class Resolve {
}
}
/**
* Most specific method applicability routine. Given a list of actual types A,
* a list of formal types F1, and a list of formal types F2, the routine determines
* as to whether the types in F1 can be considered more specific than those in F2 w.r.t.
* argument types A.
*/
class MostSpecificCheck implements MethodCheck {
boolean strict;
List<Type> actuals;
MostSpecificCheck(boolean strict, List<Type> actuals) {
this.strict = strict;
this.actuals = actuals;
}
@Override
public void argumentsAcceptable(final Env<AttrContext> env,
DeferredAttrContext deferredAttrContext,
List<Type> formals1,
List<Type> formals2,
Warner warn) {
formals2 = adjustArgs(formals2, deferredAttrContext.msym, formals1.length(), deferredAttrContext.phase.isVarargsRequired());
while (formals2.nonEmpty()) {
ResultInfo mresult = methodCheckResult(formals2.head, deferredAttrContext, warn, actuals.head);
mresult.check(null, formals1.head);
formals1 = formals1.tail;
formals2 = formals2.tail;
actuals = actuals.isEmpty() ? actuals : actuals.tail;
}
}
/**
* Create a method check context to be used during the most specific applicability check
*/
ResultInfo methodCheckResult(Type to, DeferredAttr.DeferredAttrContext deferredAttrContext,
Warner rsWarner, Type actual) {
return attr.new ResultInfo(Kinds.VAL, to,
new MostSpecificCheckContext(strict, deferredAttrContext, rsWarner, actual));
}
/**
* Subclass of method check context class that implements most specific
* method conversion. If the actual type under analysis is a deferred type
* a full blown structural analysis is carried out.
*/
class MostSpecificCheckContext extends MethodCheckContext {
Type actual;
public MostSpecificCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) {
super(strict, deferredAttrContext, rsWarner);
this.actual = actual;
}
public boolean compatible(Type found, Type req, Warner warn) {
if (!allowStructuralMostSpecific || actual == null) {
return super.compatible(found, req, warn);
} else {
switch (actual.getTag()) {
case DEFERRED:
DeferredType dt = (DeferredType) actual;
DeferredType.SpeculativeCache.Entry e = dt.speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
return (e == null || e.speculativeTree == deferredAttr.stuckTree)
? false : mostSpecific(found, req, e.speculativeTree, warn);
default:
return standaloneMostSpecific(found, req, actual, warn);
}
}
}
private boolean mostSpecific(Type t, Type s, JCTree tree, Warner warn) {
MostSpecificChecker msc = new MostSpecificChecker(t, s, warn);
msc.scan(tree);
return msc.result;
}
boolean polyMostSpecific(Type t1, Type t2, Warner warn) {
return (!t1.isPrimitive() && t2.isPrimitive())
? true : super.compatible(t1, t2, warn);
}
boolean standaloneMostSpecific(Type t1, Type t2, Type exprType, Warner warn) {
return (exprType.isPrimitive() == t1.isPrimitive()
&& exprType.isPrimitive() != t2.isPrimitive())
? true : super.compatible(t1, t2, warn);
}
/**
* Structural checker for most specific.
*/
class MostSpecificChecker extends DeferredAttr.PolyScanner {
final Type t;
final Type s;
final Warner warn;
boolean result;
MostSpecificChecker(Type t, Type s, Warner warn) {
this.t = t;
this.s = s;
this.warn = warn;
result = true;
}
@Override
void skip(JCTree tree) {
result &= standaloneMostSpecific(t, s, tree.type, warn);
}
@Override
public void visitConditional(JCConditional tree) {
if (tree.polyKind == PolyKind.STANDALONE) {
result &= standaloneMostSpecific(t, s, tree.type, warn);
} else {
super.visitConditional(tree);
}
}
@Override
public void visitApply(JCMethodInvocation tree) {
result &= (tree.polyKind == PolyKind.STANDALONE)
? standaloneMostSpecific(t, s, tree.type, warn)
: polyMostSpecific(t, s, warn);
}
@Override
public void visitNewClass(JCNewClass tree) {
result &= (tree.polyKind == PolyKind.STANDALONE)
? standaloneMostSpecific(t, s, tree.type, warn)
: polyMostSpecific(t, s, warn);
}
@Override
public void visitReference(JCMemberReference tree) {
if (types.isFunctionalInterface(t.tsym) &&
types.isFunctionalInterface(s.tsym) &&
types.asSuper(t, s.tsym) == null &&
types.asSuper(s, t.tsym) == null) {
Type desc_t = types.findDescriptorType(t);
Type desc_s = types.findDescriptorType(s);
if (types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
if (!desc_s.getReturnType().hasTag(VOID)) {
//perform structural comparison
Type ret_t = desc_t.getReturnType();
Type ret_s = desc_s.getReturnType();
result &= ((tree.refPolyKind == PolyKind.STANDALONE)
? standaloneMostSpecific(ret_t, ret_s, tree.type, warn)
: polyMostSpecific(ret_t, ret_s, warn));
} else {
return;
}
} else {
result &= false;
}
} else {
result &= MostSpecificCheckContext.super.compatible(t, s, warn);
}
}
@Override
public void visitLambda(JCLambda tree) {
if (types.isFunctionalInterface(t.tsym) &&
types.isFunctionalInterface(s.tsym) &&
types.asSuper(t, s.tsym) == null &&
types.asSuper(s, t.tsym) == null) {
Type desc_t = types.findDescriptorType(t);
Type desc_s = types.findDescriptorType(s);
if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT
|| types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
if (!desc_s.getReturnType().hasTag(VOID)) {
//perform structural comparison
Type ret_t = desc_t.getReturnType();
Type ret_s = desc_s.getReturnType();
scanLambdaBody(tree, ret_t, ret_s);
} else {
return;
}
} else {
result &= false;
}
} else {
result &= MostSpecificCheckContext.super.compatible(t, s, warn);
}
}
//where
void scanLambdaBody(JCLambda lambda, final Type t, final Type s) {
if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
result &= MostSpecificCheckContext.this.mostSpecific(t, s, lambda.body, warn);
} else {
DeferredAttr.LambdaReturnScanner lambdaScanner =
new DeferredAttr.LambdaReturnScanner() {
@Override
public void visitReturn(JCReturn tree) {
if (tree.expr != null) {
result &= MostSpecificCheckContext.this.mostSpecific(t, s, tree.expr, warn);
}
}
};
lambdaScanner.scan(lambda.body);
}
}
}
}
}
public static class InapplicableMethodException extends RuntimeException {
private static final long serialVersionUID = 0;
......@@ -1142,151 +1352,30 @@ public class Resolve {
}
//where
private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
Symbol m12 = adjustVarargs(m1, m2, useVarargs);
Symbol m22 = adjustVarargs(m2, m1, useVarargs);
Type mtype1 = types.memberType(site, m12);
Type mtype2 = types.memberType(site, m22);
//check if invocation is more specific
if (invocationMoreSpecific(env, site, m22, mtype1.getParameterTypes(), allowBoxing, useVarargs)) {
return true;
}
//perform structural check
List<Type> formals1 = mtype1.getParameterTypes();
Type lastFormal1 = formals1.last();
List<Type> formals2 = mtype2.getParameterTypes();
Type lastFormal2 = formals2.last();
ListBuffer<Type> newFormals = ListBuffer.lb();
boolean hasStructuralPoly = false;
for (Type actual : actuals) {
//perform formal argument adaptation in case actuals > formals (varargs)
Type f1 = formals1.isEmpty() ?
lastFormal1 : formals1.head;
Type f2 = formals2.isEmpty() ?
lastFormal2 : formals2.head;
//is this a structural actual argument?
boolean isStructuralPoly = actual.hasTag(DEFERRED) &&
(((DeferredType)actual).tree.hasTag(LAMBDA) ||
((DeferredType)actual).tree.hasTag(REFERENCE));
Type newFormal = f1;
if (isStructuralPoly) {
//for structural arguments only - check that corresponding formals
//are related - if so replace formal with <null>
hasStructuralPoly = true;
DeferredType dt = (DeferredType)actual;
Type t1 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m1, currentResolutionContext.step).apply(dt);
Type t2 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m2, currentResolutionContext.step).apply(dt);
if (t1.isErroneous() || t2.isErroneous() || !isStructuralSubtype(t1, t2)) {
//not structural subtypes - simply fail
return false;
} else {
newFormal = syms.botType;
}
}
newFormals.append(newFormal);
if (newFormals.length() > mtype2.getParameterTypes().length()) {
//expand m2's type so as to fit the new formal arity (varargs)
m22.type = types.createMethodTypeWithParameters(m22.type, m22.type.getParameterTypes().append(f2));
}
formals1 = formals1.isEmpty() ? formals1 : formals1.tail;
formals2 = formals2.isEmpty() ? formals2 : formals2.tail;
}
if (!hasStructuralPoly) {
//if no structural actual was found, we're done
return false;
}
//perform additional adaptation if actuals < formals (varargs)
for (Type t : formals1) {
newFormals.append(t);
}
//check if invocation (with tweaked args) is more specific
return invocationMoreSpecific(env, site, m22, newFormals.toList(), allowBoxing, useVarargs);
}
//where
private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) {
MethodResolutionContext prevContext = currentResolutionContext;
try {
currentResolutionContext = new MethodResolutionContext();
currentResolutionContext.step = allowBoxing ? BOX : BASIC;
noteWarner.clear();
Type mst = instantiate(env, site, m2, null,
types.lowerBounds(argtypes1), null,
allowBoxing, false, resolveMethodCheck, noteWarner);
return mst != null &&
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
} finally {
currentResolutionContext = prevContext;
}
}
//where
private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) {
List<Type> fromArgs = from.type.getParameterTypes();
List<Type> toArgs = to.type.getParameterTypes();
if (useVarargs &&
(from.flags() & VARARGS) != 0 &&
(to.flags() & VARARGS) != 0) {
Type varargsTypeFrom = fromArgs.last();
Type varargsTypeTo = toArgs.last();
ListBuffer<Type> args = ListBuffer.lb();
if (toArgs.length() < fromArgs.length()) {
//if we are checking a varargs method 'from' against another varargs
//method 'to' (where arity of 'to' < arity of 'from') then expand signature
//of 'to' to 'fit' arity of 'from' (this means adding fake formals to 'to'
//until 'to' signature has the same arity as 'from')
while (fromArgs.head != varargsTypeFrom) {
args.append(toArgs.head == varargsTypeTo ? types.elemtype(varargsTypeTo) : toArgs.head);
fromArgs = fromArgs.tail;
toArgs = toArgs.head == varargsTypeTo ?
toArgs :
toArgs.tail;
}
} else {
//formal argument list is same as original list where last
//argument (array type) is removed
args.appendList(toArgs.reverse().tail.reverse());
}
//append varargs element type as last synthetic formal
args.append(types.elemtype(varargsTypeTo));
Type mtype = types.createMethodTypeWithParameters(to.type, args.toList());
return new MethodSymbol(to.flags_field & ~VARARGS, to.name, mtype, to.owner);
noteWarner.clear();
int maxLength = Math.max(
Math.max(m1.type.getParameterTypes().length(), actuals.length()),
m2.type.getParameterTypes().length());
Type mst = instantiate(env, site, m2, null,
adjustArgs(types.lowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null,
allowBoxing, useVarargs, new MostSpecificCheck(!allowBoxing, actuals), noteWarner);
return mst != null &&
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
}
private List<Type> adjustArgs(List<Type> args, Symbol msym, int length, boolean allowVarargs) {
if ((msym.flags() & VARARGS) != 0 && allowVarargs) {
Type varargsElem = types.elemtype(args.last());
if (varargsElem == null) {
Assert.error("Bad varargs = " + args.last() + " " + msym);
}
List<Type> newArgs = args.reverse().tail.prepend(varargsElem).reverse();
while (newArgs.length() < length) {
newArgs = newArgs.append(newArgs.last());
}
return newArgs;
} else {
return to;
}
}
//where
boolean isStructuralSubtype(Type s, Type t) {
Type ret_s = types.findDescriptorType(s).getReturnType();
Type ret_t = types.findDescriptorType(t).getReturnType();
//covariant most specific check for function descriptor return type
if (!types.isSubtype(ret_s, ret_t)) {
return false;
return args;
}
List<Type> args_s = types.findDescriptorType(s).getParameterTypes();
List<Type> args_t = types.findDescriptorType(t).getParameterTypes();
//arity must be identical
if (args_s.length() != args_t.length()) {
return false;
}
//invariant most specific check for function descriptor parameter types
if (!types.isSameTypes(args_t, args_s)) {
return false;
}
return true;
}
//where
Type mostSpecificReturnType(Type mt1, Type mt2) {
......
......@@ -549,9 +549,6 @@ public class TransTypes extends TreeTranslator {
currentMethod = null;
tree.params = translate(tree.params);
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;
}
......@@ -785,9 +782,6 @@ public class TransTypes extends TreeTranslator {
public void visitReference(JCMemberReference tree) {
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;
}
......
......@@ -606,6 +606,42 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
}
/**
* Common supertype for all poly expression trees (lambda, method references,
* conditionals, method and constructor calls)
*/
public static abstract class JCPolyExpression extends JCExpression {
/**
* A poly expression can only be truly 'poly' in certain contexts
*/
public enum PolyKind {
/** poly expression to be treated as a standalone expression */
STANDALONE,
/** true poly expression */
POLY;
}
/** is this poly expression a 'true' poly expression? */
public PolyKind polyKind;
}
/**
* Common supertype for all functional expression trees (lambda and method references)
*/
public static abstract class JCFunctionalExpression extends JCPolyExpression {
public JCFunctionalExpression() {
//a functional expression is always a 'true' poly
polyKind = PolyKind.POLY;
}
/** target descriptor inferred for this functional expression. */
public Type descriptorType;
/** list of target types inferred for this functional expression. */
public List<TypeSymbol> targets;
}
/**
* A class definition.
*/
......@@ -1147,7 +1183,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* A ( ) ? ( ) : ( ) conditional expression
*/
public static class JCConditional extends JCExpression implements ConditionalExpressionTree {
public static class JCConditional extends JCPolyExpression implements ConditionalExpressionTree {
public JCExpression cond;
public JCExpression truepart;
public JCExpression falsepart;
......@@ -1373,7 +1409,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* A method invocation
*/
public static class JCMethodInvocation extends JCExpression implements MethodInvocationTree {
public static class JCMethodInvocation extends JCPolyExpression implements MethodInvocationTree {
public List<JCExpression> typeargs;
public JCExpression meth;
public List<JCExpression> args;
......@@ -1416,7 +1452,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* A new(...) operation.
*/
public static class JCNewClass extends JCExpression implements NewClassTree {
public static class JCNewClass extends JCPolyExpression implements NewClassTree {
public JCExpression encl;
public List<JCExpression> typeargs;
public JCExpression clazz;
......@@ -1502,18 +1538,29 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* A lambda expression.
*/
public static class JCLambda extends JCExpression implements LambdaExpressionTree {
public static class JCLambda extends JCFunctionalExpression implements LambdaExpressionTree {
public enum ParameterKind {
IMPLICIT,
EXPLICIT;
}
public List<JCVariableDecl> params;
public JCTree body;
public Type targetType;
public boolean canCompleteNormally = true;
public List<Type> inferredThrownTypes;
public ParameterKind paramKind;
public JCLambda(List<JCVariableDecl> params,
JCTree body) {
this.params = params;
this.body = body;
if (params.isEmpty() ||
params.head.vartype != null) {
paramKind = ParameterKind.EXPLICIT;
} else {
paramKind = ParameterKind.IMPLICIT;
}
}
@Override
public Tag getTag() {
......@@ -1812,15 +1859,15 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/**
* Selects a member expression.
*/
public static class JCMemberReference extends JCExpression implements MemberReferenceTree {
public static class JCMemberReference extends JCFunctionalExpression implements MemberReferenceTree {
public ReferenceMode mode;
public ReferenceKind kind;
public Name name;
public JCExpression expr;
public List<JCExpression> typeargs;
public Type targetType;
public Symbol sym;
public Type varargsElement;
public PolyKind refPolyKind;
/**
* Javac-dependent classification for member references, based
......
......@@ -946,7 +946,7 @@ public class Pretty extends JCTree.Visitor {
public void visitLambda(JCLambda tree) {
try {
print("(");
if (TreeInfo.isExplicitLambda(tree)) {
if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) {
printExprs(tree.params);
} else {
String sep = "";
......
......@@ -32,6 +32,7 @@ import com.sun.tools.javac.code.*;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import static com.sun.tools.javac.code.Flags.*;
......@@ -264,9 +265,38 @@ public class TreeInfo {
}
}
public static boolean isExplicitLambda(JCLambda lambda) {
return lambda.params.isEmpty() ||
lambda.params.head.vartype != null;
/** set 'polyKind' on given tree */
public static void setPolyKind(JCTree tree, PolyKind pkind) {
switch (tree.getTag()) {
case APPLY:
((JCMethodInvocation)tree).polyKind = pkind;
break;
case NEWCLASS:
((JCNewClass)tree).polyKind = pkind;
break;
case REFERENCE:
((JCMemberReference)tree).refPolyKind = pkind;
break;
default:
throw new AssertionError("Unexpected tree: " + tree);
}
}
/** set 'varargsElement' on given tree */
public static void setVarargsElement(JCTree tree, Type varargsElement) {
switch (tree.getTag()) {
case APPLY:
((JCMethodInvocation)tree).varargsElement = varargsElement;
break;
case NEWCLASS:
((JCNewClass)tree).varargsElement = varargsElement;
break;
case REFERENCE:
((JCMemberReference)tree).varargsElement = varargsElement;
break;
default:
throw new AssertionError("Unexpected tree: " + tree);
}
}
/** Return true if the tree corresponds to an expression statement */
......
T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.intersection.type: 1, T6722234d.A)
T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: compiler.misc.intersection.type: 1, T6722234d.A,java.lang.Object)
- compiler.misc.where.description.intersection: compiler.misc.intersection.type: 1,{(compiler.misc.where.intersection: compiler.misc.intersection.type: 1, java.lang.Object,T6722234d.I1,T6722234d.I2)}
1 error
T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.intersection.type: 1, T6722234d.A)
T6722234d.java:18:20: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: compiler.misc.intersection.type: 1, T6722234d.A,Object)
- compiler.misc.where.description.intersection: compiler.misc.intersection.type: 1,{(compiler.misc.where.intersection: compiler.misc.intersection.type: 1, Object,I1,I2)}
1 error
......@@ -59,6 +59,7 @@ compiler.misc.fatal.err.cant.locate.meth # Resolve, from Lower
compiler.misc.fatal.err.cant.close # JavaCompiler
compiler.misc.file.does.not.contain.package
compiler.misc.illegal.start.of.class.file
compiler.misc.inferred.do.not.conform.to.lower.bounds # cannot happen?
compiler.misc.kindname.annotation
compiler.misc.kindname.enum
compiler.misc.kindname.package
......@@ -68,6 +69,7 @@ compiler.misc.kindname.type.variable.bound
compiler.misc.kindname.value
compiler.misc.incompatible.eq.lower.bounds # cannot happen?
compiler.misc.no.unique.minimal.instance.exists
compiler.misc.no.unique.maximal.instance.exists # cannot happen?
compiler.misc.resume.abort # prompt for a response
compiler.misc.source.unavailable # DiagnosticSource
compiler.misc.token.bad-symbol
......
......@@ -21,7 +21,7 @@
* questions.
*/
// key: compiler.err.cant.apply.symbol
// key: compiler.err.prob.found.req
// key: compiler.misc.cyclic.inference
class CyclicInference {
......
/*
* 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.no.unique.maximal.instance.exists
class NoUniqueMaximalInstance {
<Z extends Integer> Z m() { return null; }
{ String s = m(); }
}
......@@ -25,7 +25,7 @@
// key: compiler.misc.where.description.intersection
// key: compiler.misc.intersection.type
// key: compiler.err.prob.found.req
// key: compiler.misc.inconvertible.types
// key: compiler.misc.inferred.do.not.conform.to.upper.bounds
// options: -XDdiags=where
// run: simple
......
T6939780.java:18:33: compiler.warn.diamond.redundant.args: Foo<java.lang.Number>, Foo<java.lang.Number>
T6939780.java:19:28: compiler.warn.diamond.redundant.args: Foo<java.lang.Number>, Foo<java.lang.Number>
T6939780.java:20:28: compiler.warn.diamond.redundant.args.1: Foo<java.lang.Integer>, Foo<java.lang.Number>
2 warnings
3 warnings
Neg05.java:19:48: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:19:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>)
Neg05.java:20:58: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:20:45: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>)
Neg05.java:21:43: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:21:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>)
Neg05.java:22:56: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:22:43: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>)
Neg05.java:24:48: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:24:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<java.lang.String>)
Neg05.java:25:58: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:25:45: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? extends java.lang.String>)
Neg05.java:26:43: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:26:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<?>)
Neg05.java:27:56: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:27:43: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg05.Foo<java.lang.String>, Neg05<?>.Foo<? super java.lang.String>)
Neg05.java:31:37: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:31:44: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V, Neg05.Foo<V>, Neg05<?>.Foo<java.lang.String>))
Neg05.java:32:47: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:32:54: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V, Neg05.Foo<V>, Neg05<?>.Foo<? extends java.lang.String>))
Neg05.java:33:32: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:33:39: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V, Neg05.Foo<V>, Neg05<?>.Foo<?>))
Neg05.java:34:45: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:34:52: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V, Neg05.Foo<V>, Neg05<?>.Foo<? super java.lang.String>))
Neg05.java:36:37: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:36:44: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V,Z, Neg05.Foo<V>, Neg05<?>.Foo<java.lang.String>))
Neg05.java:37:47: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:37:54: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V,Z, Neg05.Foo<V>, Neg05<?>.Foo<? extends java.lang.String>))
Neg05.java:38:32: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:38:39: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V,Z, Neg05.Foo<V>, Neg05<?>.Foo<?>))
Neg05.java:39:45: compiler.err.improperly.formed.type.inner.raw.param
Neg05.java:39:52: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg05.Foo), (compiler.misc.infer.no.conforming.instance.exists: V,Z, Neg05.Foo<V>, Neg05<?>.Foo<? super java.lang.String>))
24 errors
......@@ -4,7 +4,8 @@
*
* @summary Check that 'complex' diamond can infer type that is too specific
* @author mcimadamore
* @compile/fail/ref=Neg10.out Neg10.java -XDrawDiagnostics
* @compile/fail/ref=Neg10.out -source 7 -Xlint:-options Neg10.java -XDrawDiagnostics
* @compile Neg10.java -XDrawDiagnostics
*
*/
......
Neg10.java:16:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>)
Neg10.java:17:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>)
1 error
T6315770.java:16:42: compiler.err.prob.found.req: (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable)
T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer&java.lang.Runnable, java.lang.String)
T6315770.java:16:42: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.bounds: T, java.lang.String,java.lang.Integer,java.lang.Runnable)
T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Integer,java.lang.Runnable)
2 errors
T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, java.lang.String,java.lang.Object)
T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: T, java.lang.Integer, java.lang.String,java.lang.Object)
1 error
T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer, java.lang.String)
T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Integer,java.lang.Object)
1 error
......@@ -25,21 +25,13 @@
* @test
* @bug 8003280
* @summary Add lambda tests
* check that non-boxing method references conversion has the precedence
* @run main MethodReference25
* check that non-boxing method references is not preferred over boxing one
* @compile/fail/ref=MethodReference25.out -XDrawDiagnostics MethodReference25.java
*/
public class MethodReference25 {
class MethodReference25 {
static void assertTrue(boolean cond) {
assertionCount++;
if (!cond)
throw new AssertionError();
}
static int assertionCount = 0;
static void m(Integer i) { assertTrue(true); }
static void m(Integer i) { }
interface SAM1 {
void m(int x);
......@@ -49,11 +41,10 @@ public class MethodReference25 {
void m(Integer x);
}
static void call(int i, SAM1 s) { s.m(i); assertTrue(false); }
static void call(int i, SAM1 s) { s.m(i); }
static void call(int i, SAM2 s) { s.m(i); }
public static void main(String[] args) {
call(1, MethodReference25::m); //resolves to call(int, SAM2)
assertTrue(assertionCount == 1);
call(1, MethodReference25::m); //ambiguous
}
}
MethodReference25.java:48:9: compiler.err.ref.ambiguous: call, kindname.method, call(int,MethodReference25.SAM1), MethodReference25, kindname.method, call(int,MethodReference25.SAM2), MethodReference25
1 error
/*
* @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check strict method conversion does not allow loose method reference conversion
* @compile/fail/ref=MethodReference26.out -XDrawDiagnostics MethodReference26.java
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary check strict method conversion allows loose method reference conversion
* @compile MethodReference26.java
*/
class MethodReference26 {
......@@ -18,6 +39,6 @@ class MethodReference26 {
static void call(Integer i, SAM s) { }
static void test() {
call(1, MethodReference26::m); //ambiguous
call(1, MethodReference26::m); //ok
}
}
MethodReference26.java:21:9: compiler.err.ref.ambiguous: call, kindname.method, call(int,MethodReference26.SAM), MethodReference26, kindname.method, call(java.lang.Integer,MethodReference26.SAM), MethodReference26
1 error
......@@ -60,9 +60,9 @@ public class MethodReference43 {
static void m(SAM1 s) { assertTrue(false); }
static void m(SAM2 s) { assertTrue(true); }
static void m(SAM2 s) { assertTrue(false); }
static void m(SAM3 s) { assertTrue(false); }
static void m(SAM4 s) { assertTrue(false); }
static void m(SAM4 s) { assertTrue(true); }
public static void main(String[] args) {
m(Foo::new);
......
......@@ -27,7 +27,7 @@
* @summary Add lambda tests
* check nested case of overload resolution and lambda parameter inference
* @author Maurizio Cimadamore
* @compile TargetType01.java
* @compile/fail/ref=TargetType01.out -XDrawDiagnostics TargetType01.java
*/
class TargetType01 {
......@@ -43,7 +43,6 @@ class TargetType01 {
static String M(F_S_S f){ return null; }
static {
//ambiguity here - the compiler does not try all the combinations!
M(x1 -> { return M( x2 -> { return x1 + x2; });});
M(x1 -> { return M( x2 -> { return x1 + x2; });}); //ambiguous
}
}
TargetType01.java:46:9: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
TargetType01.java:46:26: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
2 errors
......@@ -4,7 +4,7 @@
* @summary Add lambda tests
* check complex case of target typing
* @author Maurizio Cimadamore
* @compile/fail/ref=TargetType06.out -XDrawDiagnostics TargetType06.java
* @compile TargetType06.java
*/
import java.util.List;
......
TargetType06.java:25:23: compiler.err.cant.apply.symbol: kindname.method, map, TargetType06.Function<B,B>, @510, kindname.class, TargetType06, (compiler.misc.cyclic.inference: B)
1 error
TargetType10.java:17:11: compiler.err.cant.apply.symbol: kindname.method, compose, TargetType10.Function<B,C>,TargetType10.Function<A,? extends B>, @500,@515, kindname.class, TargetType10.Test, (compiler.misc.cyclic.inference: B,A)
TargetType10.java:17:18: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: B,A)
1 error
......@@ -4,7 +4,7 @@
* @summary Add lambda tests
* check that wildcards in the target method of a lambda conversion is handled correctly
* @author Maurizio Cimadamore
* @compile/fail/ref=TargetType11.out -Xlint:unchecked -XDrawDiagnostics TargetType11.java
* @compile TargetType11.java
*/
class TargetType11 {
......
TargetType11.java:16:61: compiler.warn.unchecked.varargs.non.reifiable.type: TargetType11.Predicate<? super T>
TargetType11.java:20:32: compiler.err.cant.apply.symbol: kindname.method, and, TargetType11.Predicate<? super T>[], @706,@718, kindname.class, TargetType11.Test, (compiler.misc.cyclic.inference: T)
1 error
1 warning
TargetType14.java:20:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: TargetType14.SAM<java.lang.String>, TargetType14.SAM<java.lang.Integer>)
TargetType14.java:20:29: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer, java.lang.String)
1 error
......@@ -26,8 +26,8 @@ class TargetType21 {
void test() {
call(x -> { throw new Exception(); }); //ambiguous
call(x -> { System.out.println(""); }); //ok - resolves to call(SAM2)
call(x -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference
call(x -> { return null; }); ////ok - resolves to call(SAM1)
call(x -> { System.out.println(""); }); //ambiguous
call(x -> { return (Object) null; }); //cyclic inference
call(x -> { return null; }); //ambiguous
}
}
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM2), TargetType21
TargetType21.java:30:9: compiler.err.cant.apply.symbols: kindname.method, call, @737,{(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, <R,A>call(TargetType21.SAM3<R,A>), (compiler.misc.cyclic.inference: A))}
2 errors
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
TargetType21.java:28:14: compiler.err.incompatible.thrown.types.in.lambda: java.lang.Exception
TargetType21.java:29:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A)
TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
5 errors
TargetType26.java:16:7: compiler.err.cant.apply.symbol: kindname.method, call, Z, @340, kindname.class, TargetType26, (compiler.misc.cyclic.inference: Z)
TargetType26.java:16:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
1 error
TargetType27.java:18:9: compiler.err.cant.apply.symbol: kindname.method, m, TargetType27.F<A,R>, @490, kindname.class, TargetType27, (compiler.misc.cyclic.inference: R)
TargetType27.java:18:10: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: R)
1 error
TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: TargetType28.SuperFoo<java.lang.Number>, TargetType28.SuperFoo<java.lang.String>)
TargetType28.java:21:33: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: TargetType28.SuperFoo<java.lang.Number>, TargetType28.SuperFoo<java.lang.Integer>)
TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.Number, java.lang.Number,java.lang.String)
TargetType28.java:21:33: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.Number, java.lang.Number,java.lang.Integer)
2 errors
TargetType39.java:19:9: compiler.err.cant.apply.symbol: kindname.method, call, TargetType39.SAM<U,V>, @442, kindname.class, TargetType39, (compiler.misc.cyclic.inference: U)
TargetType39.java:20:9: compiler.err.cant.apply.symbol: kindname.method, call, TargetType39.SAM<U,V>, @479, kindname.class, TargetType39, (compiler.misc.cyclic.inference: V)
TargetType39.java:19:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: U)
TargetType39.java:20:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: V)
2 errors
......@@ -3,7 +3,7 @@
* @bug 8003280
* @summary Add lambda tests
* compiler crashes during flow analysis as it fails to report diagnostics during attribution
* @compile/fail/ref=TargetType45.out -XDrawDiagnostics TargetType45.java
* @compile TargetType45.java
*/
class TargetType45 {
......
TargetType45.java:27:28: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: U,V, (compiler.misc.inconvertible.types: TargetType45.Mapper<java.lang.String,java.lang.Integer>, TargetType45.Mapper<? super java.lang.Object,? extends java.lang.Integer>))
1 error
TargetType50.java:25:28: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.String, java.lang.String,java.lang.Object)
TargetType50.java:26:28: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.String, java.lang.String,java.lang.Object)
TargetType50.java:25:28: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: TargetType50.Sink<java.lang.Object>, TargetType50.Sink<java.lang.String>)
TargetType50.java:26:28: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: TargetType50.Sink<java.lang.Object>, TargetType50.Sink<java.lang.String>)
2 errors
......@@ -21,12 +21,46 @@
* questions.
*/
// key: compiler.err.prob.found.req
// key: compiler.misc.inferred.do.not.conform.to.lower.bounds
/*
* @test
* @summary smoke test for combinator-like stuck analysis
* @author Maurizio Cimadamore
* @compile TargetType51.java
*/
import java.util.Comparator;
class TargetType51 {
interface SimpleMapper<T, U> {
T map(U t);
}
interface SimpleList<X> {
SimpleList<X> sort(Comparator<? super X> c);
}
static class Person {
String getName() { return ""; }
}
<T, U extends Comparable<? super U>> Comparator<T> comparing(SimpleMapper<U, T> mapper) { return null; }
static class F<U extends Comparable<? super U>, T> {
F(SimpleMapper<U, T> f) { }
}
import java.util.*;
void testAssignmentContext(SimpleList<Person> list, boolean cond) {
SimpleList<Person> p1 = list.sort(comparing(Person::getName));
SimpleList<Person> p2 = list.sort(comparing(x->x.getName()));
SimpleList<Person> p3 = list.sort(cond ? comparing(Person::getName) : comparing(x->x.getName()));
SimpleList<Person> p4 = list.sort((cond ? comparing(Person::getName) : comparing(x->x.getName())));
}
class InferredDoNotConformToLower {
<X extends Number> List<X> m() { return null; }
{ List<? super String> lss = this.m(); }
void testMethodContext(SimpleList<Person> list, boolean cond) {
testMethodContext(list.sort(comparing(Person::getName)), true);
testMethodContext(list.sort(comparing(x->x.getName())), true);
testMethodContext(list.sort(cond ? comparing(Person::getName) : comparing(x->x.getName())), true);
testMethodContext(list.sort((cond ? comparing(Person::getName) : comparing(x->x.getName()))), true);
}
}
/*
* @test /nodynamiccopyright/
* @summary uncatched sam conversion failure exception lead to javac crash
* @compile/fail/ref=TargetType52.out -XDrawDiagnostics TargetType52.java
*/
class TargetType52 {
interface FI<T extends CharSequence, V extends java.util.AbstractList<T>> {
T m(V p);
}
void m(FI<? extends CharSequence, ? extends java.util.ArrayList<? extends CharSequence>> fip) { }
void test() {
m(p -> p.get(0));
}
}
TargetType52.java:15:9: compiler.err.cant.apply.symbol: kindname.method, m, TargetType52.FI<? extends java.lang.CharSequence,? extends java.util.ArrayList<? extends java.lang.CharSequence>>, @449, kindname.class, TargetType52, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.no.suitable.functional.intf.inst: TargetType52.FI<java.lang.CharSequence,java.util.ArrayList<? extends java.lang.CharSequence>>))
1 error
......@@ -3,7 +3,7 @@
* @bug 8003280
* @summary Add lambda tests
* check that that void compatibility affects overloading as expected
* @compile/fail/ref=VoidCompatibility.out -XDrawDiagnostics VoidCompatibility.java
* @compile VoidCompatibility.java
*/
class VoidCompatibility {
......@@ -14,13 +14,13 @@ class VoidCompatibility {
void schedule(Thunk<?> t) { }
void test() {
schedule(() -> System.setProperty("done", "true")); //2
schedule(() -> System.setProperty("done", "true")); //non-void most specific
schedule(() -> { System.setProperty("done", "true"); }); //1
schedule(() -> { return System.setProperty("done", "true"); }); //2
schedule(() -> System.out.println("done")); //1
schedule(() -> { System.out.println("done"); }); //1
schedule(Thread::yield); //1
schedule(Thread::getAllStackTraces); //ambiguous
schedule(Thread::getAllStackTraces); //non-void most specific
schedule(Thread::interrupted); //1 (most specific)
}
}
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
2 errors
......@@ -149,8 +149,7 @@ public class SamConversionComboTest {
return false; //ambiguous target type
}
else if(lambdaBody == LambdaBody.IMPLICIT) {
if(returnValue != ReturnValue.INTEGER) //ambiguous target type
return false;
return false;
}
else { //explicit parameter type
if(fInterface.getParameterType().equals("Integer")) //ambiguous target type
......
......@@ -149,14 +149,6 @@ public class SamConversion {
test2(A::method3, 4);
test2(new A()::method4, 5);
test2(new A()::method5, 6);
A a = new A(A::method1); //A(Foo f) called
assertTrue(a.method2(1) == 11);
assertTrue(a.method4(1) == 11);
assertTrue(a.method5(1) == 11);
A a2 = new A(new A()::method2); //A(Bar b) called
assertTrue(a2.method2(1) == 12);
assertTrue(a2.method4(1) == 12);
assertTrue(a2.method5(1) == 12);
}
/**
......@@ -279,7 +271,7 @@ public class SamConversion {
testConditionalExpression(false);
testLambdaExpressionBody();
assertTrue(assertionCount == 38);
assertTrue(assertionCount == 32);
}
static class MyException extends Exception {}
......
......@@ -186,10 +186,7 @@ public class SamConversionComboTest {
if(context != Context.CONSTRUCTOR && fInterface != FInterface.C && methodDef == MethodDef.METHOD6)
//method that throws exceptions not thrown by the interface method is a mismatch
return false;
if(context == Context.CONSTRUCTOR &&
methodReference != MethodReference.METHOD1 &&
methodReference != MethodReference.METHOD2 &&
methodReference != MethodReference.METHOD3)//ambiguous reference
if(context == Context.CONSTRUCTOR)
return false;
return true;
}
......
InferenceTest_neg5.java:14:13: compiler.err.cant.apply.symbol: kindname.method, method1, InferenceTest_neg5.SAM1<X>, @419, kindname.class, InferenceTest_neg5, (compiler.misc.cyclic.inference: X)
InferenceTest_neg5.java:14:21: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: X)
1 error
......@@ -23,44 +23,44 @@
@TraceResolve(keys={"compiler.err.ref.ambiguous"})
class PrimitiveOverReferenceVarargsAmbiguous {
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_byte(byte... b) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_byte(Byte... b) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_short(short... s) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_short(Short... s) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_int(int... i) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_int(Integer... i) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_long(long... l) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_long(Long... l) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_float(float... f) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_float(Float... f) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_double(double... d) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_double(Double... d) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_char(char... c) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_char(Character... c) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS, mostSpecific=true)
static void m_bool(boolean... z) {}
@Candidate(applicable=Phase.VARARGS, mostSpecific=false)
@Candidate(applicable=Phase.VARARGS)
static void m_bool(Boolean... z) {}
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册