mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +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());
|
||||
List<Type> argtypes = desc.getParameterTypes();
|
||||
Resolve.MethodCheck referenceCheck = rs.resolveMethodCheck;
|
||||
|
||||
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
|
||||
rs.resolveMemberReference(that.pos(), localEnv, that,
|
||||
that.expr.type, that.name, argtypes, typeargtypes, true, rs.resolveMethodCheck);
|
||||
if (resultInfo.checkContext.inferenceContext().free(argtypes)) {
|
||||
referenceCheck = rs.new MethodReferenceCheck(resultInfo.checkContext.inferenceContext());
|
||||
}
|
||||
|
||||
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;
|
||||
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.dup(newMethodTemplate(
|
||||
desc.getReturnType().hasTag(VOID) ? Type.noType : desc.getReturnType(),
|
||||
lookupHelper.argtypes,
|
||||
typeargtypes));
|
||||
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes));
|
||||
|
||||
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()) {
|
||||
refType = types.createMethodTypeWithReturn(refType,
|
||||
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.Infer.InferenceContext;
|
||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
|
||||
import com.sun.tools.javac.comp.Resolve.ReferenceLookupHelper;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
|
@ -96,6 +95,17 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
types = Types.instance(context);
|
||||
Names names = Names.instance(context);
|
||||
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 */
|
||||
|
@ -479,12 +489,10 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
|
||||
ResultInfo resultInfo;
|
||||
InferenceContext inferenceContext;
|
||||
Env<AttrContext> env;
|
||||
|
||||
public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
|
||||
this.resultInfo = resultInfo;
|
||||
this.inferenceContext = deferredAttrContext.inferenceContext;
|
||||
this.env = dt.env.dup(dt.tree, dt.env.info.dup());
|
||||
dt.tree.accept(this);
|
||||
dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
|
||||
return Type.noType;
|
||||
|
@ -533,18 +541,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
} catch (Types.FunctionDescriptorLookupError ex) {
|
||||
checkContext.report(null, ex.getDiagnostic());
|
||||
}
|
||||
JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), env,
|
||||
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) {
|
||||
switch (tree.sym.kind) {
|
||||
//note: as argtypes are erroneous types, type-errors must
|
||||
//have been caused by arity mismatch
|
||||
case Kinds.ABSENT_MTH:
|
||||
|
@ -560,17 +557,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
}
|
||||
|
||||
/** an empty deferred attribution context - all methods throw exceptions */
|
||||
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!");
|
||||
}
|
||||
};
|
||||
final DeferredAttrContext emptyDeferredAttrContext;
|
||||
|
||||
/**
|
||||
* 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()) {
|
||||
return List.nil();
|
||||
} else {
|
||||
return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
|
||||
return stuckVarsInternal(tree, resultInfo.pt, env, resultInfo.checkContext.inferenceContext());
|
||||
}
|
||||
}
|
||||
//where
|
||||
private List<Type> stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
|
||||
StuckChecker sc = new StuckChecker(pt, inferenceContext);
|
||||
private List<Type> stuckVarsInternal(JCTree tree, Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
|
||||
StuckChecker sc = new StuckChecker(pt, env, inferenceContext);
|
||||
sc.scan(tree);
|
||||
return List.from(sc.stuckVars);
|
||||
}
|
||||
|
@ -753,11 +740,13 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
class StuckChecker extends PolyScanner {
|
||||
|
||||
Type pt;
|
||||
Env<AttrContext> env;
|
||||
Infer.InferenceContext inferenceContext;
|
||||
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.env = env;
|
||||
this.inferenceContext = inferenceContext;
|
||||
}
|
||||
|
||||
|
@ -791,18 +780,41 @@ public class DeferredAttr extends JCTree.Visitor {
|
|||
|
||||
Type descType = types.findDescriptorType(pt);
|
||||
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
|
||||
stuckVars.addAll(freeArgVars);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scanLambdaBody(JCLambda lambda, final Type pt) {
|
||||
if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
|
||||
stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
|
||||
stuckVars.addAll(stuckVarsInternal(lambda.body, pt, env, inferenceContext));
|
||||
} else {
|
||||
LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
|
||||
@Override
|
||||
public void visitReturn(JCReturn tree) {
|
||||
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();
|
||||
}
|
||||
|
||||
ListBuffer<Type> args = ListBuffer.lb();
|
||||
for (int i = 0; i < tree.args.length(); i ++) {
|
||||
args.append(Type.noType);
|
||||
}
|
||||
List<Type> args = rs.dummyArgs(tree.args.length());
|
||||
|
||||
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
|
||||
Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
|
||||
return rec == null ?
|
||||
|
|
|
@ -149,7 +149,7 @@ public class Infer {
|
|||
inferenceException.clear();
|
||||
try {
|
||||
DeferredAttr.DeferredAttrContext deferredAttrContext =
|
||||
resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn);
|
||||
resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn);
|
||||
|
||||
resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext,
|
||||
argtypes, mt.getParameterTypes(), warn);
|
||||
|
@ -225,32 +225,32 @@ public class Infer {
|
|||
inferenceContext.restvars(), mt.getReturnType(), to);
|
||||
}
|
||||
}
|
||||
//where
|
||||
private Type returnConstraintTarget(Type from, Type to) {
|
||||
if (from.hasTag(VOID)) {
|
||||
return syms.voidType;
|
||||
} else if (to.hasTag(NONE)) {
|
||||
return from.isPrimitive() ? from : syms.objectType;
|
||||
} else if (from.hasTag(UNDETVAR) && to.isPrimitive()) {
|
||||
if (!allowGraphInference) {
|
||||
//if legacy, just return boxed type
|
||||
return types.boxedClass(to).type;
|
||||
}
|
||||
//if graph inference we need to skip conflicting boxed bounds...
|
||||
UndetVar uv = (UndetVar)from;
|
||||
for (Type t : uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
|
||||
Type boundAsPrimitive = types.unboxedType(t);
|
||||
if (boundAsPrimitive == null) continue;
|
||||
if (types.isConvertible(boundAsPrimitive, to)) {
|
||||
//effectively skip return-type constraint generation (compatibility)
|
||||
return syms.objectType;
|
||||
}
|
||||
}
|
||||
|
||||
Type returnConstraintTarget(Type from, Type to) {
|
||||
if (from.hasTag(VOID)) {
|
||||
return syms.voidType;
|
||||
} else if (to.hasTag(NONE)) {
|
||||
return from.isPrimitive() ? from : syms.objectType;
|
||||
} else if (from.hasTag(UNDETVAR) && to.isPrimitive()) {
|
||||
if (!allowGraphInference) {
|
||||
//if legacy, just return boxed type
|
||||
return types.boxedClass(to).type;
|
||||
} else {
|
||||
return to;
|
||||
}
|
||||
//if graph inference we need to skip conflicting boxed bounds...
|
||||
UndetVar uv = (UndetVar)from;
|
||||
for (Type t : uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
|
||||
Type boundAsPrimitive = types.unboxedType(t);
|
||||
if (boundAsPrimitive == null) continue;
|
||||
if (types.isConvertible(boundAsPrimitive, to)) {
|
||||
//effectively skip return-type constraint generation (compatibility)
|
||||
return syms.objectType;
|
||||
}
|
||||
}
|
||||
return types.boxedClass(to).type;
|
||||
} else {
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer cyclic inference variables as described in 15.12.2.8.
|
||||
|
@ -1337,9 +1337,6 @@ public class Infer {
|
|||
/** list of inference vars in this context */
|
||||
List<Type> inferencevars;
|
||||
|
||||
/** backed up inference variables */
|
||||
List<Type> saved_undet;
|
||||
|
||||
java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
|
||||
new java.util.HashMap<FreeTypeListener, List<Type>>();
|
||||
|
||||
|
|
|
@ -584,6 +584,13 @@ public class Resolve {
|
|||
try {
|
||||
currentResolutionContext = new MethodResolutionContext();
|
||||
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;
|
||||
return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes,
|
||||
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,
|
||||
* 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
|
||||
* context might contain inference variables.
|
||||
|
@ -2576,7 +2632,8 @@ public class Resolve {
|
|||
Name name, List<Type> argtypes,
|
||||
List<Type> typeargtypes,
|
||||
boolean boxingAllowed,
|
||||
MethodCheck methodCheck) {
|
||||
MethodCheck methodCheck,
|
||||
InferenceContext inferenceContext) {
|
||||
MethodResolutionPhase maxPhase = boxingAllowed ? VARARITY : BASIC;
|
||||
|
||||
ReferenceLookupHelper boundLookupHelper;
|
||||
|
@ -2599,7 +2656,7 @@ public class Resolve {
|
|||
Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, methodCheck, boundLookupHelper);
|
||||
|
||||
//step 2 - unbound lookup
|
||||
ReferenceLookupHelper unboundLookupHelper = boundLookupHelper.unboundLookup();
|
||||
ReferenceLookupHelper unboundLookupHelper = boundLookupHelper.unboundLookup(inferenceContext);
|
||||
Env<AttrContext> unboundEnv = env.dup(env.tree, env.info.dup());
|
||||
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
|
||||
* method returns an dummy lookup helper.
|
||||
*/
|
||||
ReferenceLookupHelper unboundLookup() {
|
||||
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||
//dummy loopkup helper that always return 'methodNotFound'
|
||||
return new ReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase) {
|
||||
@Override
|
||||
ReferenceLookupHelper unboundLookup() {
|
||||
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
|
@ -2793,14 +2850,15 @@ public class Resolve {
|
|||
}
|
||||
|
||||
@Override
|
||||
ReferenceLookupHelper unboundLookup() {
|
||||
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||
if (TreeInfo.isStaticSelector(referenceTree.expr, names) &&
|
||||
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,
|
||||
site, argtypes, typeargtypes, maxPhase);
|
||||
} else {
|
||||
return super.unboundLookup();
|
||||
return super.unboundLookup(inferenceContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2836,7 +2894,7 @@ public class Resolve {
|
|||
}
|
||||
|
||||
@Override
|
||||
ReferenceLookupHelper unboundLookup() {
|
||||
ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
|
||||
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: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: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: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
|
||||
|
|
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