mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-16 00:54:38 +02:00
8016175: Add bottom-up type-checking support for unambiguous method references
Type-checking of non-overloaded method references should be independent from target-type Reviewed-by: jjg, vromero
This commit is contained in:
parent
941752ea25
commit
99b0413d48
16 changed files with 360 additions and 83 deletions
|
@ -2708,10 +2708,21 @@ public class Attr extends JCTree.Visitor {
|
||||||
|
|
||||||
setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
|
setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
|
||||||
List<Type> argtypes = desc.getParameterTypes();
|
List<Type> argtypes = desc.getParameterTypes();
|
||||||
|
Resolve.MethodCheck referenceCheck = rs.resolveMethodCheck;
|
||||||
|
|
||||||
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
|
if (resultInfo.checkContext.inferenceContext().free(argtypes)) {
|
||||||
rs.resolveMemberReference(that.pos(), localEnv, that,
|
referenceCheck = rs.new MethodReferenceCheck(resultInfo.checkContext.inferenceContext());
|
||||||
that.expr.type, that.name, argtypes, typeargtypes, true, rs.resolveMethodCheck);
|
}
|
||||||
|
|
||||||
|
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult = null;
|
||||||
|
List<Type> saved_undet = resultInfo.checkContext.inferenceContext().save();
|
||||||
|
try {
|
||||||
|
refResult = rs.resolveMemberReference(that.pos(), localEnv, that, that.expr.type,
|
||||||
|
that.name, argtypes, typeargtypes, true, referenceCheck,
|
||||||
|
resultInfo.checkContext.inferenceContext());
|
||||||
|
} finally {
|
||||||
|
resultInfo.checkContext.inferenceContext().rollback(saved_undet);
|
||||||
|
}
|
||||||
|
|
||||||
Symbol refSym = refResult.fst;
|
Symbol refSym = refResult.fst;
|
||||||
Resolve.ReferenceLookupHelper lookupHelper = refResult.snd;
|
Resolve.ReferenceLookupHelper lookupHelper = refResult.snd;
|
||||||
|
@ -2823,17 +2834,24 @@ public class Attr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
that.sym = refSym.baseSymbol();
|
|
||||||
that.kind = lookupHelper.referenceKind(that.sym);
|
|
||||||
|
|
||||||
ResultInfo checkInfo =
|
ResultInfo checkInfo =
|
||||||
resultInfo.dup(newMethodTemplate(
|
resultInfo.dup(newMethodTemplate(
|
||||||
desc.getReturnType().hasTag(VOID) ? Type.noType : desc.getReturnType(),
|
desc.getReturnType().hasTag(VOID) ? Type.noType : desc.getReturnType(),
|
||||||
lookupHelper.argtypes,
|
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes));
|
||||||
typeargtypes));
|
|
||||||
|
|
||||||
Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
|
Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
|
||||||
|
|
||||||
|
if (that.kind.isUnbound() &&
|
||||||
|
resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
|
||||||
|
//re-generate inference constraints for unbound receiver
|
||||||
|
if (!types.isSubtype(resultInfo.checkContext.inferenceContext().asFree(argtypes.head), exprType)) {
|
||||||
|
//cannot happen as this has already been checked - we just need
|
||||||
|
//to regenerate the inference constraints, as that has been lost
|
||||||
|
//as a result of the call to inferenceContext.save()
|
||||||
|
Assert.error("Can't get here");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!refType.isErroneous()) {
|
if (!refType.isErroneous()) {
|
||||||
refType = types.createMethodTypeWithReturn(refType,
|
refType = types.createMethodTypeWithReturn(refType,
|
||||||
adjustMethodReturnType(lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
|
adjustMethodReturnType(lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
|
||||||
|
|
|
@ -34,15 +34,14 @@ import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.comp.Attr.ResultInfo;
|
import com.sun.tools.javac.comp.Attr.ResultInfo;
|
||||||
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
||||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
||||||
|
import com.sun.tools.javac.comp.Resolve.ReferenceLookupHelper;
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
|
|
||||||
import javax.tools.JavaFileObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
@ -96,6 +95,17 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
types = Types.instance(context);
|
types = Types.instance(context);
|
||||||
Names names = Names.instance(context);
|
Names names = Names.instance(context);
|
||||||
stuckTree = make.Ident(names.empty).setType(Type.stuckType);
|
stuckTree = make.Ident(names.empty).setType(Type.stuckType);
|
||||||
|
emptyDeferredAttrContext =
|
||||||
|
new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
|
||||||
|
@Override
|
||||||
|
void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
|
||||||
|
Assert.error("Empty deferred context!");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
void complete() {
|
||||||
|
Assert.error("Empty deferred context!");
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** shared tree for stuck expressions */
|
/** shared tree for stuck expressions */
|
||||||
|
@ -479,12 +489,10 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
|
|
||||||
ResultInfo resultInfo;
|
ResultInfo resultInfo;
|
||||||
InferenceContext inferenceContext;
|
InferenceContext inferenceContext;
|
||||||
Env<AttrContext> env;
|
|
||||||
|
|
||||||
public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
|
public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
|
||||||
this.resultInfo = resultInfo;
|
this.resultInfo = resultInfo;
|
||||||
this.inferenceContext = deferredAttrContext.inferenceContext;
|
this.inferenceContext = deferredAttrContext.inferenceContext;
|
||||||
this.env = dt.env.dup(dt.tree, dt.env.info.dup());
|
|
||||||
dt.tree.accept(this);
|
dt.tree.accept(this);
|
||||||
dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
|
dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
|
||||||
return Type.noType;
|
return Type.noType;
|
||||||
|
@ -533,18 +541,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
} catch (Types.FunctionDescriptorLookupError ex) {
|
} catch (Types.FunctionDescriptorLookupError ex) {
|
||||||
checkContext.report(null, ex.getDiagnostic());
|
checkContext.report(null, ex.getDiagnostic());
|
||||||
}
|
}
|
||||||
JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), env,
|
switch (tree.sym.kind) {
|
||||||
attr.memberReferenceQualifierResult(tree));
|
|
||||||
ListBuffer<Type> argtypes = ListBuffer.lb();
|
|
||||||
for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
|
|
||||||
argtypes.append(Type.noType);
|
|
||||||
}
|
|
||||||
JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
|
|
||||||
mref2.expr = exprTree;
|
|
||||||
Pair<Symbol, ?> lookupRes =
|
|
||||||
rs.resolveMemberReference(tree, env, mref2, exprTree.type,
|
|
||||||
tree.name, argtypes.toList(), null, true, rs.arityMethodCheck);
|
|
||||||
switch (lookupRes.fst.kind) {
|
|
||||||
//note: as argtypes are erroneous types, type-errors must
|
//note: as argtypes are erroneous types, type-errors must
|
||||||
//have been caused by arity mismatch
|
//have been caused by arity mismatch
|
||||||
case Kinds.ABSENT_MTH:
|
case Kinds.ABSENT_MTH:
|
||||||
|
@ -560,17 +557,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** an empty deferred attribution context - all methods throw exceptions */
|
/** an empty deferred attribution context - all methods throw exceptions */
|
||||||
final DeferredAttrContext emptyDeferredAttrContext =
|
final DeferredAttrContext emptyDeferredAttrContext;
|
||||||
new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, null, null, null) {
|
|
||||||
@Override
|
|
||||||
void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
|
|
||||||
Assert.error("Empty deferred context!");
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
void complete() {
|
|
||||||
Assert.error("Empty deferred context!");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a list of types possibly containing one or more deferred types
|
* Map a list of types possibly containing one or more deferred types
|
||||||
|
@ -668,12 +655,12 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
|
if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
|
||||||
return List.nil();
|
return List.nil();
|
||||||
} else {
|
} else {
|
||||||
return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
|
return stuckVarsInternal(tree, resultInfo.pt, env, resultInfo.checkContext.inferenceContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
private List<Type> stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
|
private List<Type> stuckVarsInternal(JCTree tree, Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
|
||||||
StuckChecker sc = new StuckChecker(pt, inferenceContext);
|
StuckChecker sc = new StuckChecker(pt, env, inferenceContext);
|
||||||
sc.scan(tree);
|
sc.scan(tree);
|
||||||
return List.from(sc.stuckVars);
|
return List.from(sc.stuckVars);
|
||||||
}
|
}
|
||||||
|
@ -753,11 +740,13 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
class StuckChecker extends PolyScanner {
|
class StuckChecker extends PolyScanner {
|
||||||
|
|
||||||
Type pt;
|
Type pt;
|
||||||
|
Env<AttrContext> env;
|
||||||
Infer.InferenceContext inferenceContext;
|
Infer.InferenceContext inferenceContext;
|
||||||
Set<Type> stuckVars = new LinkedHashSet<Type>();
|
Set<Type> stuckVars = new LinkedHashSet<Type>();
|
||||||
|
|
||||||
StuckChecker(Type pt, Infer.InferenceContext inferenceContext) {
|
StuckChecker(Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
|
||||||
this.pt = pt;
|
this.pt = pt;
|
||||||
|
this.env = env;
|
||||||
this.inferenceContext = inferenceContext;
|
this.inferenceContext = inferenceContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,18 +780,41 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
|
|
||||||
Type descType = types.findDescriptorType(pt);
|
Type descType = types.findDescriptorType(pt);
|
||||||
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
|
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
|
||||||
|
Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
|
||||||
|
if (freeArgVars.nonEmpty()) {
|
||||||
|
//perform arity-based check
|
||||||
|
JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
|
||||||
|
attr.memberReferenceQualifierResult(tree));
|
||||||
|
ListBuffer<Type> argtypes = ListBuffer.lb();
|
||||||
|
for (Type t : descType.getParameterTypes()) {
|
||||||
|
argtypes.append(Type.noType);
|
||||||
|
}
|
||||||
|
JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
|
||||||
|
mref2.expr = exprTree;
|
||||||
|
Pair<Symbol, ReferenceLookupHelper> lookupRes =
|
||||||
|
rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
|
||||||
|
tree.name, argtypes.toList(), null, true, rs.arityMethodCheck,
|
||||||
|
inferenceContext);
|
||||||
|
Symbol res = tree.sym = lookupRes.fst;
|
||||||
|
if (res.kind >= Kinds.ERRONEOUS ||
|
||||||
|
res.type.hasTag(FORALL) ||
|
||||||
|
(res.flags() & Flags.VARARGS) != 0 ||
|
||||||
|
(TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
|
||||||
|
exprTree.type.isRaw())) {
|
||||||
stuckVars.addAll(freeArgVars);
|
stuckVars.addAll(freeArgVars);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void scanLambdaBody(JCLambda lambda, final Type pt) {
|
void scanLambdaBody(JCLambda lambda, final Type pt) {
|
||||||
if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
|
if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
|
||||||
stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
|
stuckVars.addAll(stuckVarsInternal(lambda.body, pt, env, inferenceContext));
|
||||||
} else {
|
} else {
|
||||||
LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
|
LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
|
||||||
@Override
|
@Override
|
||||||
public void visitReturn(JCReturn tree) {
|
public void visitReturn(JCReturn tree) {
|
||||||
if (tree.expr != null) {
|
if (tree.expr != null) {
|
||||||
stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext));
|
stuckVars.addAll(stuckVarsInternal(tree.expr, pt, env, inferenceContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -950,12 +962,9 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
site = site.getUpperBound();
|
site = site.getUpperBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
ListBuffer<Type> args = ListBuffer.lb();
|
List<Type> args = rs.dummyArgs(tree.args.length());
|
||||||
for (int i = 0; i < tree.args.length(); i ++) {
|
|
||||||
args.append(Type.noType);
|
|
||||||
}
|
|
||||||
|
|
||||||
Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.<Type>nil(), MethodResolutionPhase.VARARITY) {
|
Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
|
||||||
@Override
|
@Override
|
||||||
Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
|
Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
|
||||||
return rec == null ?
|
return rec == null ?
|
||||||
|
|
|
@ -225,8 +225,8 @@ public class Infer {
|
||||||
inferenceContext.restvars(), mt.getReturnType(), to);
|
inferenceContext.restvars(), mt.getReturnType(), to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//where
|
|
||||||
private Type returnConstraintTarget(Type from, Type to) {
|
Type returnConstraintTarget(Type from, Type to) {
|
||||||
if (from.hasTag(VOID)) {
|
if (from.hasTag(VOID)) {
|
||||||
return syms.voidType;
|
return syms.voidType;
|
||||||
} else if (to.hasTag(NONE)) {
|
} else if (to.hasTag(NONE)) {
|
||||||
|
@ -1337,9 +1337,6 @@ public class Infer {
|
||||||
/** list of inference vars in this context */
|
/** list of inference vars in this context */
|
||||||
List<Type> inferencevars;
|
List<Type> inferencevars;
|
||||||
|
|
||||||
/** backed up inference variables */
|
|
||||||
List<Type> saved_undet;
|
|
||||||
|
|
||||||
java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
|
java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
|
||||||
new java.util.HashMap<FreeTypeListener, List<Type>>();
|
new java.util.HashMap<FreeTypeListener, List<Type>>();
|
||||||
|
|
||||||
|
|
|
@ -584,6 +584,13 @@ public class Resolve {
|
||||||
try {
|
try {
|
||||||
currentResolutionContext = new MethodResolutionContext();
|
currentResolutionContext = new MethodResolutionContext();
|
||||||
currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
|
currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK;
|
||||||
|
if (env.tree.hasTag(JCTree.Tag.REFERENCE)) {
|
||||||
|
//method/constructor references need special check class
|
||||||
|
//to handle inference variables in 'argtypes' (might happen
|
||||||
|
//during an unsticking round)
|
||||||
|
currentResolutionContext.methodCheck =
|
||||||
|
new MethodReferenceCheck(resultInfo.checkContext.inferenceContext());
|
||||||
|
}
|
||||||
MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
|
MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase;
|
||||||
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
||||||
step.isBoxingRequired(), step.isVarargsRequired(), warn);
|
step.isBoxingRequired(), step.isVarargsRequired(), warn);
|
||||||
|
@ -773,6 +780,14 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
List<Type> dummyArgs(int length) {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
for (int i = 0 ; i < length ; i++) {
|
||||||
|
buf.append(Type.noType);
|
||||||
|
}
|
||||||
|
return buf.toList();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main method applicability routine. Given a list of actual types A,
|
* Main method applicability routine. Given a list of actual types A,
|
||||||
* a list of formal types F, determines whether the types in A are
|
* a list of formal types F, determines whether the types in A are
|
||||||
|
@ -850,6 +865,47 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MethodReferenceCheck extends AbstractMethodCheck {
|
||||||
|
|
||||||
|
InferenceContext pendingInferenceContext;
|
||||||
|
|
||||||
|
MethodReferenceCheck(InferenceContext pendingInferenceContext) {
|
||||||
|
this.pendingInferenceContext = pendingInferenceContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
|
||||||
|
ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn);
|
||||||
|
mresult.check(pos, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResultInfo methodCheckResult(final boolean varargsCheck, Type to,
|
||||||
|
final DeferredAttr.DeferredAttrContext deferredAttrContext, Warner rsWarner) {
|
||||||
|
CheckContext checkContext = new MethodCheckContext(!deferredAttrContext.phase.isBoxingRequired(), deferredAttrContext, rsWarner) {
|
||||||
|
MethodCheckDiag methodDiag = varargsCheck ?
|
||||||
|
MethodCheckDiag.VARARG_MISMATCH : MethodCheckDiag.ARG_MISMATCH;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
|
found = pendingInferenceContext.asFree(found);
|
||||||
|
req = infer.returnConstraintTarget(found, req);
|
||||||
|
return super.compatible(found, req, warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
|
reportMC(pos, methodDiag, deferredAttrContext.inferenceContext, details);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new MethodResultInfo(to, checkContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
|
||||||
|
return new MostSpecificCheck(strict, actuals);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check context to be used during method applicability checks. A method check
|
* Check context to be used during method applicability checks. A method check
|
||||||
* context might contain inference variables.
|
* context might contain inference variables.
|
||||||
|
@ -2576,7 +2632,8 @@ public class Resolve {
|
||||||
Name name, List<Type> argtypes,
|
Name name, List<Type> argtypes,
|
||||||
List<Type> typeargtypes,
|
List<Type> typeargtypes,
|
||||||
boolean boxingAllowed,
|
boolean boxingAllowed,
|
||||||
MethodCheck methodCheck) {
|
MethodCheck methodCheck,
|
||||||
|
InferenceContext inferenceContext) {
|
||||||
MethodResolutionPhase maxPhase = boxingAllowed ? VARARITY : BASIC;
|
MethodResolutionPhase maxPhase = boxingAllowed ? VARARITY : BASIC;
|
||||||
|
|
||||||
ReferenceLookupHelper boundLookupHelper;
|
ReferenceLookupHelper boundLookupHelper;
|
||||||
|
@ -2599,7 +2656,7 @@ public class Resolve {
|
||||||
Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, methodCheck, boundLookupHelper);
|
Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, methodCheck, boundLookupHelper);
|
||||||
|
|
||||||
//step 2 - unbound lookup
|
//step 2 - unbound lookup
|
||||||
ReferenceLookupHelper unboundLookupHelper = boundLookupHelper.unboundLookup();
|
ReferenceLookupHelper unboundLookupHelper = boundLookupHelper.unboundLookup(inferenceContext);
|
||||||
Env<AttrContext> unboundEnv = env.dup(env.tree, env.info.dup());
|
Env<AttrContext> unboundEnv = env.dup(env.tree, env.info.dup());
|
||||||
Symbol unboundSym = lookupMethod(unboundEnv, env.tree.pos(), site.tsym, methodCheck, unboundLookupHelper);
|
Symbol unboundSym = lookupMethod(unboundEnv, env.tree.pos(), site.tsym, methodCheck, unboundLookupHelper);
|
||||||
|
|
||||||
|
@ -2739,11 +2796,11 @@ public class Resolve {
|
||||||
* Returns an unbound version of this lookup helper. By default, this
|
* Returns an unbound version of this lookup helper. By default, this
|
||||||
* method returns an dummy lookup helper.
|
* method returns an dummy lookup helper.
|
||||||
*/
|
*/
|
||||||
ReferenceLookupHelper unboundLookup() {
|
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||||
//dummy loopkup helper that always return 'methodNotFound'
|
//dummy loopkup helper that always return 'methodNotFound'
|
||||||
return new ReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase) {
|
return new ReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase) {
|
||||||
@Override
|
@Override
|
||||||
ReferenceLookupHelper unboundLookup() {
|
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@ -2793,14 +2850,15 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ReferenceLookupHelper unboundLookup() {
|
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||||
if (TreeInfo.isStaticSelector(referenceTree.expr, names) &&
|
if (TreeInfo.isStaticSelector(referenceTree.expr, names) &&
|
||||||
argtypes.nonEmpty() &&
|
argtypes.nonEmpty() &&
|
||||||
(argtypes.head.hasTag(NONE) || types.isSubtypeUnchecked(argtypes.head, site))) {
|
(argtypes.head.hasTag(NONE) ||
|
||||||
|
types.isSubtypeUnchecked(inferenceContext.asFree(argtypes.head), site))) {
|
||||||
return new UnboundMethodReferenceLookupHelper(referenceTree, name,
|
return new UnboundMethodReferenceLookupHelper(referenceTree, name,
|
||||||
site, argtypes, typeargtypes, maxPhase);
|
site, argtypes, typeargtypes, maxPhase);
|
||||||
} else {
|
} else {
|
||||||
return super.unboundLookup();
|
return super.unboundLookup(inferenceContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2836,7 +2894,7 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ReferenceLookupHelper unboundLookup() {
|
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
langtools/test/tools/javac/lambda/MethodReference68.java
Normal file
23
langtools/test/tools/javac/lambda/MethodReference68.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile/fail/ref=MethodReference68.out -XDrawDiagnostics MethodReference68.java
|
||||||
|
*/
|
||||||
|
class MethodReference68 {
|
||||||
|
interface F<X> {
|
||||||
|
String m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Foo {
|
||||||
|
String getName() { return ""; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
<Z> void g(F<Z> fz, Z... zs) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
g(Foo::getName);
|
||||||
|
g(Foo::getName, 1); //incompatible constraints, Z <: Foo, Z :> Integer
|
||||||
|
}
|
||||||
|
}
|
2
langtools/test/tools/javac/lambda/MethodReference68.out
Normal file
2
langtools/test/tools/javac/lambda/MethodReference68.out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
MethodReference68.java:21:10: compiler.err.cant.apply.symbol: kindname.method, g, MethodReference68.F<Z>,Z[], @493,int, kindname.class, MethodReference68, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, MethodReference68.Foo,java.lang.Object)
|
||||||
|
1 error
|
21
langtools/test/tools/javac/lambda/MethodReference69.java
Normal file
21
langtools/test/tools/javac/lambda/MethodReference69.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile/fail/ref=MethodReference69.out -XDrawDiagnostics MethodReference69.java
|
||||||
|
*/
|
||||||
|
class MethodReference69 {
|
||||||
|
interface F<X> {
|
||||||
|
String m(Integer x1, X x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Foo {
|
||||||
|
String getNameAt(Integer i) { return ""; }
|
||||||
|
}
|
||||||
|
|
||||||
|
<Z> void g(F<Z> fz) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
g(Foo::getName);
|
||||||
|
}
|
||||||
|
}
|
2
langtools/test/tools/javac/lambda/MethodReference69.out
Normal file
2
langtools/test/tools/javac/lambda/MethodReference69.out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
MethodReference69.java:19:12: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, getName, , , (compiler.misc.location: kindname.class, MethodReference69.Foo, null))
|
||||||
|
1 error
|
28
langtools/test/tools/javac/lambda/MethodReference70.java
Normal file
28
langtools/test/tools/javac/lambda/MethodReference70.java
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile/fail/ref=MethodReference70.out -XDrawDiagnostics MethodReference70.java
|
||||||
|
*/
|
||||||
|
class MethodReference70 {
|
||||||
|
interface F<X> {
|
||||||
|
void m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface G<X> {
|
||||||
|
Integer m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m1(Integer i) { }
|
||||||
|
|
||||||
|
void m2(Integer i) { }
|
||||||
|
void m2(String i) { }
|
||||||
|
|
||||||
|
<Z> void g(F<Z> fz) { }
|
||||||
|
<Z> void g(G<Z> gz) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
g(this::m1); //ok
|
||||||
|
g(this::m2); //ambiguous (stuck!)
|
||||||
|
}
|
||||||
|
}
|
3
langtools/test/tools/javac/lambda/MethodReference70.out
Normal file
3
langtools/test/tools/javac/lambda/MethodReference70.out
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
MethodReference70.java:26:10: compiler.err.ref.ambiguous: g, kindname.method, <Z>g(MethodReference70.F<Z>), MethodReference70, kindname.method, <Z>g(MethodReference70.G<Z>), MethodReference70
|
||||||
|
MethodReference70.java:26:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
|
||||||
|
2 errors
|
26
langtools/test/tools/javac/lambda/MethodReference71.java
Normal file
26
langtools/test/tools/javac/lambda/MethodReference71.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile/fail/ref=MethodReference71.out -XDrawDiagnostics MethodReference71.java
|
||||||
|
*/
|
||||||
|
class MethodReference71 {
|
||||||
|
interface F<X> {
|
||||||
|
void m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface G<X> {
|
||||||
|
Integer m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m1(Integer i) { }
|
||||||
|
void m2(Integer... i) { }
|
||||||
|
|
||||||
|
<Z> void g(F<Z> f) { }
|
||||||
|
<Z> void g(G<Z> g) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
g(this::m1); //ok
|
||||||
|
g(this::m2); //ambiguous (stuck!)
|
||||||
|
}
|
||||||
|
}
|
3
langtools/test/tools/javac/lambda/MethodReference71.out
Normal file
3
langtools/test/tools/javac/lambda/MethodReference71.out
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
MethodReference71.java:24:10: compiler.err.ref.ambiguous: g, kindname.method, <Z>g(MethodReference71.F<Z>), MethodReference71, kindname.method, <Z>g(MethodReference71.G<Z>), MethodReference71
|
||||||
|
MethodReference71.java:24:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
|
||||||
|
2 errors
|
20
langtools/test/tools/javac/lambda/MethodReference72.java
Normal file
20
langtools/test/tools/javac/lambda/MethodReference72.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile/fail/ref=MethodReference72.out -XDrawDiagnostics MethodReference72.java
|
||||||
|
*/
|
||||||
|
class MethodReference72 {
|
||||||
|
interface F<X> {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void m(X... x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m1(Integer i) { }
|
||||||
|
|
||||||
|
<Z> void g(F<Z> f) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
g(this::m1); //?
|
||||||
|
}
|
||||||
|
}
|
2
langtools/test/tools/javac/lambda/MethodReference72.out
Normal file
2
langtools/test/tools/javac/lambda/MethodReference72.out
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
MethodReference72.java:18:9: compiler.err.cant.apply.symbol: kindname.method, g, MethodReference72.F<Z>, @420, kindname.class, MethodReference72, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m1, java.lang.Integer, Z[], kindname.class, MethodReference72, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: Z[], java.lang.Integer)))))
|
||||||
|
1 error
|
|
@ -1,7 +1,7 @@
|
||||||
TargetType60.java:54:21: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam0), TargetType60, kindname.method, <U>g(TargetType60.Sam1<U>), TargetType60
|
TargetType60.java:54:21: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam0), TargetType60, kindname.method, <U>g(TargetType60.Sam1<U>), TargetType60
|
||||||
TargetType60.java:55:21: compiler.err.ref.ambiguous: g, kindname.method, <U>g(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>g(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
TargetType60.java:55:21: compiler.err.ref.ambiguous: g, kindname.method, <U>g(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>g(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
||||||
TargetType60.java:60:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
TargetType60.java:60:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
||||||
TargetType60.java:60:28: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, n1, java.lang.String, TargetType60, kindname.class, TargetType60, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: TargetType60, java.lang.String)))))
|
TargetType60.java:60:29: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, n1(java.lang.String))
|
||||||
TargetType60.java:61:29: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, n2(TargetType60,java.lang.String))
|
TargetType60.java:61:29: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, n2(TargetType60,java.lang.String))
|
||||||
TargetType60.java:62:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
TargetType60.java:62:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
||||||
TargetType60.java:63:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
TargetType60.java:63:27: compiler.err.ref.ambiguous: u, kindname.method, <U>u(TargetType60.Sam1<U>), TargetType60, kindname.method, <U>u(TargetType60.Sam2<U,java.lang.String>), TargetType60
|
||||||
|
|
65
langtools/test/tools/javac/lambda/TargetType76.java
Normal file
65
langtools/test/tools/javac/lambda/TargetType76.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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 8016175
|
||||||
|
* @summary Add bottom-up type-checking support for unambiguous method references
|
||||||
|
* @compile TargetType76.java
|
||||||
|
*/
|
||||||
|
class TargetType76 {
|
||||||
|
|
||||||
|
interface Function<X, Y> {
|
||||||
|
Y m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OfRef<T> { }
|
||||||
|
|
||||||
|
interface Supplier<X> {
|
||||||
|
X make();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Stream<X> { }
|
||||||
|
|
||||||
|
interface Node<E> {
|
||||||
|
Spliterator<E> spliterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Spliterator<X> {
|
||||||
|
Spliterator<X> spliterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefTestData<T, I> implements OfRef<T> {
|
||||||
|
RefTestData(I state,
|
||||||
|
Function<I, Stream<T>> streamFn,
|
||||||
|
Function<I, Spliterator<T>> splitrFn) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
<O> OfRef<O> ofCollection(Node<O> collection) {
|
||||||
|
return new RefTestData<>(collection,
|
||||||
|
x->stream(x::spliterator),
|
||||||
|
Node::spliterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
<S> Stream<S> stream(Supplier<? extends Spliterator<S>> supplier) { return null; }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue