8016175: Add bottom-up type-checking support for unambiguous method references
Summary: Type-checking of non-overloaded method references should be independent from target-type
Reviewed-by: jjg, vromero
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 17 14:04:01 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 17 14:09:46 2013 +0100
@@ -2708,10 +2708,21 @@
setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
List<Type> argtypes = desc.getParameterTypes();
-
- Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
- rs.resolveMemberReference(that.pos(), localEnv, that,
- that.expr.type, that.name, argtypes, typeargtypes, true, rs.resolveMethodCheck);
+ Resolve.MethodCheck referenceCheck = 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 @@
}
}
- 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()));
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Wed Jul 17 14:04:01 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Wed Jul 17 14:09:46 2013 +0100
@@ -34,15 +34,14 @@
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 @@
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 @@
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 @@
} 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 @@
}
/** 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 @@
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 @@
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 @@
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 @@
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 ?
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Wed Jul 17 14:04:01 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Wed Jul 17 14:09:46 2013 +0100
@@ -149,7 +149,7 @@
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 @@
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;
+
+ 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;
}
- //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;
}
+ return types.boxedClass(to).type;
+ } else {
+ return to;
}
+ }
/**
* Infer cyclic inference variables as described in 15.12.2.8.
@@ -1337,9 +1337,6 @@
/** 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>>();
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jul 17 14:04:01 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jul 17 14:09:46 2013 +0100
@@ -584,6 +584,13 @@
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 @@
}
};
+ 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 @@
}
};
+ 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 @@
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 @@
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 @@
* 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 @@
}
@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 @@
}
@Override
- ReferenceLookupHelper unboundLookup() {
+ ReferenceLookupHelper unboundLookup(InferenceContext inferenceContext) {
return this;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference68.java Wed Jul 17 14:09:46 2013 +0100
@@ -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
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference68.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference69.java Wed Jul 17 14:09:46 2013 +0100
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference69.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference70.java Wed Jul 17 14:09:46 2013 +0100
@@ -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!)
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference70.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference71.java Wed Jul 17 14:09:46 2013 +0100
@@ -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!)
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference71.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference72.java Wed Jul 17 14:09:46 2013 +0100
@@ -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); //?
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference72.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- a/langtools/test/tools/javac/lambda/TargetType60.out Wed Jul 17 14:04:01 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType60.out Wed Jul 17 14:09:46 2013 +0100
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/TargetType76.java Wed Jul 17 14:09:46 2013 +0100
@@ -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; }
+}