8016175: Add bottom-up type-checking support for unambiguous method references
authormcimadamore
Wed, 17 Jul 2013 14:09:46 +0100
changeset 18910 c967bfda9283
parent 18909 8f9fc5d876e4
child 18911 dcc1e26a8c9c
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
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/lambda/MethodReference68.java
langtools/test/tools/javac/lambda/MethodReference68.out
langtools/test/tools/javac/lambda/MethodReference69.java
langtools/test/tools/javac/lambda/MethodReference69.out
langtools/test/tools/javac/lambda/MethodReference70.java
langtools/test/tools/javac/lambda/MethodReference70.out
langtools/test/tools/javac/lambda/MethodReference71.java
langtools/test/tools/javac/lambda/MethodReference71.out
langtools/test/tools/javac/lambda/MethodReference72.java
langtools/test/tools/javac/lambda/MethodReference72.out
langtools/test/tools/javac/lambda/TargetType60.out
langtools/test/tools/javac/lambda/TargetType76.java
--- 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; }
+}