changeset 1445:56419f06ad92

Enhancement: Add support for more aggressive type-inference Experimental aggressive inference support can be enabled using the flag -XDuseGraphInference. The new inferencer (disabled by default) solves a number of outstanding problems in the legacy JDK 5/6/7 type-inferencer (which means it is also slightly backwards incompatible). Examples: *) Foo<Number> fn = new Foo<>(1); *) Set<String> ss = listInt.map(x->x.toString()).into(new HashSet<>); *) <Z> void call(SAM<Z> x, SAM<Z> y) { ... } call(() -> Collections.emptyList(), () -> new ArrayList<String>()); Misc fixes: *) remove unused class in com/sun/runtime *) fix build.properties to generate right amount of stubs *) fix regression tests failures triggered when running against lambda binary snapshot
author mcimadamore
date Fri, 03 Aug 2012 12:48:20 +0100
parents 3504d7a0115a
children 18edb8e7d1ee
files make/build.properties src/share/classes/com/sun/runtime/DefenderMethod.java src/share/classes/com/sun/tools/javac/code/Source.java src/share/classes/com/sun/tools/javac/code/Symtab.java src/share/classes/com/sun/tools/javac/code/Type.java src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java src/share/classes/com/sun/tools/javac/comp/GraphInfer.java src/share/classes/com/sun/tools/javac/comp/Infer.java src/share/classes/com/sun/tools/javac/comp/InferFactory.java src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/resources/compiler.properties src/share/classes/com/sun/tools/javac/util/List.java test/tools/javac/6758789/T6758789b.out test/tools/javac/Diagnostics/6722234/T6722234b_1.out test/tools/javac/Diagnostics/6722234/T6722234b_2.out test/tools/javac/Diagnostics/6799605/T6799605.out test/tools/javac/api/TestJavacTaskScanner.java test/tools/javac/cast/7123100/T7123100a.out test/tools/javac/defender/Pos01.java test/tools/javac/diags/examples.not-yet.txt test/tools/javac/diags/examples/CantApplyDiamond1.java test/tools/javac/diags/examples/IncompatibleEqUpperBounds.java test/tools/javac/diags/examples/IncompatibleTypes1.java test/tools/javac/diags/examples/InferNoConformingAssignment.java test/tools/javac/diags/examples/InferredDoNotConformToBounds.java test/tools/javac/diags/examples/InferredDoNotConformToEq.java test/tools/javac/diags/examples/InferredDoNotConformToLower.java test/tools/javac/diags/examples/InferredDoNotConformToUpper.java test/tools/javac/diags/examples/WhereCaptured.java test/tools/javac/diags/examples/WhereCaptured1.java test/tools/javac/generics/7015430/T7015430.out test/tools/javac/generics/7151802/T7151802.out test/tools/javac/generics/diamond/neg/Neg06.out test/tools/javac/generics/diamond/neg/Neg07.out test/tools/javac/generics/diamond/neg/Neg10.java test/tools/javac/generics/diamond/neg/Neg10.out test/tools/javac/generics/inference/6315770/T6315770.out test/tools/javac/generics/inference/6611449/T6611449.out test/tools/javac/generics/inference/6638712/T6638712b.out test/tools/javac/generics/inference/6638712/T6638712d.out test/tools/javac/generics/inference/6638712/T6638712e.out test/tools/javac/generics/inference/6650759/T6650759m.out test/tools/javac/generics/inference/7086601/T7086601a.out test/tools/javac/lambda/TargetType10.java test/tools/javac/lambda/TargetType10.out test/tools/javac/lambda/TargetType20.java test/tools/javac/lambda/TargetType20.out test/tools/javac/multicatch/Neg07.out
diffstat 52 files changed, 2089 insertions(+), 814 deletions(-) [+]
line wrap: on
line diff
--- a/make/build.properties	Mon Jul 30 13:34:28 2012 -0700
+++ b/make/build.properties	Fri Aug 03 12:48:20 2012 +0100
@@ -164,8 +164,7 @@
 # The API can be provided by using a suitable boot.java.home
 # or by setting import.jdk
 require.latest.jdk.files = \
-    com/sun/tools/javac/nio/*.java \
-	com/sun/runtime/*.java
+    com/sun/tools/javac/nio/*.java
 
 # The following files in the import jdk source directory are required
 # in order to compile the files defined in ${require.latest.jdk.files}
@@ -176,21 +175,14 @@
 # generator were to be improved -- e.g. by removing unnecessary imports.
 #
 import.jdk.stub.files = \
-    java/io/File.java \
-    java/nio/file/**.java \
-    java/nio/file/attribute/**.java \
-    java/nio/file/spi/**.java \
-    java/nio/channels/AsynchronousChannel.java \
-    java/nio/channels/AsynchronousFileChannel.java \
-    java/nio/channels/CompletionHandler.java \
-    java/nio/channels/SeekableByteChannel.java \
-    java/lang/invoke/**.java \
-    java/lang/ReflectiveOperationException.java \
-    java/lang/NoSuchMethodException.java \
-    java/lang/IllegalAccessException.java \
-    sun/invoke/**.java \
-    sun/invoke/util/**.java \
-    sun/invoke/empty/**.java
+        java/io/File.java \
+        java/nio/file/**.java \
+        java/nio/file/attribute/**.java \
+        java/nio/file/spi/**.java \
+        java/nio/channels/AsynchronousChannel.java \
+        java/nio/channels/AsynchronousFileChannel.java \
+        java/nio/channels/CompletionHandler.java \
+        java/nio/channels/SeekableByteChannel.java
 
 # The following value is used by the main jtreg target.
 # An empty value means all tests
--- a/src/share/classes/com/sun/runtime/DefenderMethod.java	Mon Jul 30 13:34:28 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-package com.sun.runtime;
-
-import java.lang.annotation.*;
-
-
-/**
- *
- * @author Maurizio Cimadamore
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface DefenderMethod {
-    String className();
-    String methodName();
-    String methodSignature();
-}
--- a/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Fri Aug 03 12:48:20 2012 +0100
@@ -212,6 +212,9 @@
     public boolean allowEffectivelyFinalInInnerClasses() {
         return compareTo(JDK1_8) >= 0;
     }
+    public boolean allowBetterInference() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Aug 03 12:48:20 2012 +0100
@@ -161,7 +161,6 @@
     public final Type autoCloseableType;
     public final Type trustMeType;
     public final Type lambdaMetafactory;
-    public final Type defenderMethodType;
 
     /** The symbol representing the length field of an array.
      */
@@ -497,7 +496,6 @@
         trustMeType = enterClass("java.lang.SafeVarargs");
 		nativeHeaderType = enterClass("javax.tools.annotation.GenerateNativeHeader");
         lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory");
-        defenderMethodType = enterClass("com.sun.runtime.DefenderMethod");
 
         synthesizeEmptyTypeIfMissing(autoCloseableType, PUBLIC | INTERFACE);
         synthesizeEmptyTypeIfMissing(cloneableType, PUBLIC | INTERFACE);
--- a/src/share/classes/com/sun/tools/javac/code/Type.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java	Fri Aug 03 12:48:20 2012 +0100
@@ -30,6 +30,11 @@
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.code.Symbol.*;
 
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+
 import javax.lang.model.type.*;
 
 import static com.sun.tools.javac.code.Flags.*;
@@ -69,6 +74,9 @@
 
     /** Constant type: no type at all. */
     public static final JCNoType noType = new JCNoType(NONE);
+    
+    /** Constant type: proto type of all poly types. */
+    public static final JCNoType anyPoly = new JCNoType(NONE);
 
     /** If this switch is turned on, the names of type variables
      *  and anonymous classes are printed with hashcodes appended.
@@ -1108,11 +1116,16 @@
         public boolean isErroneous() { return qtype.isErroneous(); }
     }
 
+    /**
+     * The type of a generic method type. It consists of a method type and
+     * a list of method type-parameters that are used within the method
+     * type.
+     */
     public static class ForAll extends DelegatedType implements ExecutableType {
         public List<Type> tvars;
 
         public ForAll(List<Type> tvars, Type qtype) {
-            super(FORALL, qtype);
+            super(FORALL, (MethodType)qtype);
             this.tvars = tvars;
         }
 
@@ -1163,33 +1176,112 @@
         }
     }
 
-    /** A class for instantiatable variables, for use during type
-     *  inference.
-     */
-    public static class UndetVar extends DelegatedType {
-        public List<Type> lobounds = List.nil();
-        public List<Type> hibounds = List.nil();
-        public Type inst = null;
-
-        @Override
-        public <R,S> R accept(Type.Visitor<R,S> v, S s) {
-            return v.visitUndetVar(this, s);
-        }
-
-        public UndetVar(Type origin) {
-            super(UNDETVAR, origin);
-        }
-
-        public String toString() {
-            if (inst != null) return inst.toString();
-            else return qtype + "?";
-        }
-
-        public Type baseType() {
-            if (inst != null) return inst.baseType();
-            else return this;
-        }
-    }
+    /** A class for inference variables, for use during method/diamond type
+      *  inference. An inference variable has upper/lower bounds and a set
+      *  of equality constraints. Such bounds are set during subtyping, type-containment,
+      *  type-equality checks, when the types being tested contain inference variables.
+      *  A change listener can be attached to an inference variable, to receive notifications
+      *  whenever the bounds of an inference variable change.
+      */
+     public static class UndetVar extends DelegatedType {
+         
+         /** Inference variable change listener. The listener method is called
+          *  whenever a change to the inference variable's bounds occurs
+          */
+         public interface UndetVarListener {
+             /** called when some inference variable bounds (of given kinds ibs) change */
+             void varChanged(UndetVar uv, Set<InferenceBound> ibs);
+         }
+         
+         /**
+          * Inference variable bound kinds
+          */
+         public enum InferenceBound {
+             /** upper bounds */
+             UPPER,
+             /** lower bounds */
+             LOWER,
+             /** equality constraints */
+             EQ;
+         }
+         
+         /** inference variable bounds */
+         private Map<InferenceBound, List<Type>> bounds;
+         
+         /** inference variable's inferred type (set from Infer.java) */
+         public Type inst = null;
+         
+         /** inference variable's change listener */
+         public UndetVarListener listener = null;
+ 
+         @Override
+         public <R,S> R accept(Type.Visitor<R,S> v, S s) {
+             return v.visitUndetVar(this, s);
+         }
+ 
+         public UndetVar(TypeVar origin, boolean includeBounds, Types types) {
+             super(UNDETVAR, origin);
+             bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class);
+             bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil());
+             bounds.put(InferenceBound.LOWER, List.<Type>nil());
+             bounds.put(InferenceBound.EQ, List.<Type>nil());
+         }
+ 
+         public String toString() {
+             if (inst != null) return inst.toString();
+             else return qtype + "?";
+         }
+ 
+         public Type baseType() {
+             if (inst != null) return inst.baseType();
+             else return this;
+         }
+         
+         /** get all bounds of a given kind */
+         public List<Type> getBounds(InferenceBound... ibs) {
+             ListBuffer<Type> buf = ListBuffer.lb();
+             for (InferenceBound ib : ibs) {
+                buf.appendList(bounds.get(ib));
+             }
+             return buf.toList();
+         }
+         
+         /** add a bound of a given kind - this might trigger listener notification */
+         public void addBound(InferenceBound ib, Type bound, Types types) {
+             List<Type> prevBounds = bounds.get(ib);
+             for (Type b : prevBounds) {
+                 if (types.isSameType(b, bound))
+                     return;
+             }
+             bounds.put(ib, prevBounds.prepend(bound));
+             notifyChange(EnumSet.of(ib));
+         }
+         
+         /** replace types in all bounds - this might trigger listener notification */
+         public void substBounds(List<Type> from, List<Type> to, Types types) {
+             EnumSet<InferenceBound> changed = EnumSet.noneOf(InferenceBound.class);
+             Map<InferenceBound, List<Type>> bounds2 = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class);
+             for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) {
+                 InferenceBound ib = _entry.getKey();
+                 List<Type> prevBounds = _entry.getValue();
+                 List<Type> newBounds = types.subst(prevBounds, from, to);
+                 bounds2.put(ib, newBounds);
+                 if (prevBounds != newBounds) {
+                     changed.add(ib);
+                 }
+             }
+             if (!changed.isEmpty()) {
+                 bounds = bounds2;
+                 notifyChange(changed);
+             }
+         }
+         
+         private void notifyChange(EnumSet<InferenceBound> ibs) {
+             if (listener != null) {
+                 listener.varChanged(this, ibs);
+             }
+         }
+     }
 
     /** Represents VOID or NONE.
      */
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Aug 03 12:48:20 2012 +0100
@@ -35,6 +35,7 @@
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Scope.CompoundScope;
+import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
 import com.sun.tools.javac.comp.Check;
 
 import static com.sun.tools.javac.code.Type.*;
@@ -575,11 +576,6 @@
             else if (t.tag == TYPEVAR) {
                 return isSubtypeUnchecked(t.getUpperBound(), s, warn);
             }
-            else if (s.tag == UNDETVAR) {
-                UndetVar uv = (UndetVar)s;
-                if (uv.inst != null)
-                    return isSubtypeUnchecked(t, uv.inst, warn);
-            }
             else if (!s.isRaw()) {
                 Type t2 = asSuper(t, s.tsym);
                 if (t2 != null && t2.isRaw()) {
@@ -764,10 +760,7 @@
                     return false;
                 }
 
-                if (t.inst != null)
-                    return isSubtypeNoCapture(t.inst, s); // TODO: ", warn"?
-
-                t.hibounds = t.hibounds.prepend(s);
+                t.addBound(InferenceBound.UPPER, s, Types.this);
                 return true;
             }
 
@@ -835,9 +828,7 @@
                 undet.qtype == s ||
                 s.tag == ERROR ||
                 s.tag == BOT) return true;
-            if (undet.inst != null)
-                return isSubtype(s, undet.inst);
-            undet.lobounds = undet.lobounds.prepend(s);
+            undet.addBound(InferenceBound.LOWER, s, this);
             return true;
         }
         default:
@@ -982,18 +973,8 @@
                 if (t == s || t.qtype == s || s.tag == ERROR || s.tag == UNKNOWN)
                     return true;
 
-                if (t.inst != null)
-                    return visit(t.inst, s);
-
-                t.inst = fromUnknownFun.apply(s);
-                for (List<Type> l = t.lobounds; l.nonEmpty(); l = l.tail) {
-                    if (!isSubtype(l.head, t.inst))
-                        return false;
-                }
-                for (List<Type> l = t.hibounds; l.nonEmpty(); l = l.tail) {
-                    if (!isSubtype(t.inst, l.head))
-                        return false;
-                }
+                t.addBound(InferenceBound.EQ, s, Types.this);
+
                 return true;
             }
 
@@ -1004,19 +985,6 @@
         };
     // </editor-fold>
 
-    // <editor-fold defaultstate="collapsed" desc="fromUnknownFun">
-    /**
-     * A mapping that turns all unknown types in this type to fresh
-     * unknown variables.
-     */
-    public Mapping fromUnknownFun = new Mapping("fromUnknownFun") {
-            public Type apply(Type t) {
-                if (t.tag == UNKNOWN) return new UndetVar(t);
-                else return t.map(this);
-            }
-        };
-    // </editor-fold>
-
     // <editor-fold defaultstate="collapsed" desc="Contains Type">
     public boolean containedBy(Type t, Type s) {
         switch (t.tag) {
@@ -1028,24 +996,12 @@
                     case UNBOUND: //similar to ? extends Object
                     case EXTENDS: {
                         Type bound = upperBound(s);
-                        // We should check the new upper bound against any of the
-                        // undetvar's lower bounds.
-                        for (Type t2 : undetvar.lobounds) {
-                            if (!isSubtype(t2, bound))
-                                return false;
-                        }
-                        undetvar.hibounds = undetvar.hibounds.prepend(bound);
+                        undetvar.addBound(InferenceBound.UPPER, bound, this);
                         break;
                     }
                     case SUPER: {
                         Type bound = lowerBound(s);
-                        // We should check the new lower bound against any of the
-                        // undetvar's lower bounds.
-                        for (Type t2 : undetvar.hibounds) {
-                            if (!isSubtype(bound, t2))
-                                return false;
-                        }
-                        undetvar.lobounds = undetvar.lobounds.prepend(bound);
+                        undetvar.addBound(InferenceBound.LOWER, bound, this);
                         break;
                     }
                 }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Aug 03 12:48:20 2012 +0100
@@ -25,12 +25,12 @@
 
 package com.sun.tools.javac.comp;
 
-import com.sun.tools.javac.comp.Infer.InferenceContext;
 import java.util.*;
 import java.util.Set;
 import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
@@ -115,7 +115,7 @@
         memberEnter = MemberEnter.instance(context);
         make = TreeMaker.instance(context);
         enter = Enter.instance(context);
-        infer = Infer.instance(context);
+        infer = InferFactory.instance(context).getInfer();
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         types = Types.instance(context);
@@ -247,11 +247,11 @@
         Type owntype = found;
         if (owntype.tag != ERROR && resultInfo.pt.tag != METHOD && resultInfo.pt.tag != FORALL) {
             if (inferenceContext.free(found)) {
-                inferenceContext.addPendingCheck(new Infer.PendingCheck() {
+                inferenceContext.addPendingCheck(new PendingCheck() {
                     public void eval() {
                         ResultInfo pendingResult =
-                                resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
-                        check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
+                                resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+                        check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult);
                     }
                 });
                 return tree.type = resultInfo.pt;
@@ -619,7 +619,7 @@
         for (JCExpression arg : trees) {
             Type argtype = allowPoly && TreeInfo.isPoly(arg) ?
                     new DeferredAttr.DeferredType<JCExpression>(arg, env) :
-                    attribExpr(arg, env, Infer.anyPoly);
+                    attribExpr(arg, env, Type.anyPoly);
             argtypes.append(argtype);
         }
         return argtypes.toList();
@@ -1775,7 +1775,7 @@
 
             // Check that value of resulting type is admissible in the
             // current context.  Also, capture the return type
-            result = check(tree, capture(restype), VAL, resultInfo);
+            result = check(tree, restype, VAL, resultInfo);
 
             if (localEnv.info.varArgs)
                 Assert.check(result.isErroneous() || tree.varargsElement != null);
@@ -1946,7 +1946,7 @@
             // Resolve the called constructor under the assumption
             // that we are referring to a superclass instance of the
             // current instance (JLS ???).
-            else {
+            else if (!TreeInfo.isDiamond(tree)) {
                 //the following code alters some of the fields in the current
                 //AttrContext - hence, the current context must be dup'ed in
                 //order to avoid downstream failures
@@ -2054,6 +2054,7 @@
     interface DiamondHelper {
         DiagnosticPosition pos();
         List<JCExpression> argumentExpressions();
+        void attribTree(Symbol constrSymbol, Type constrType);
     }
     
     Type attribDiamond(Env<AttrContext> env,
@@ -2069,6 +2070,10 @@
             public List<JCExpression> argumentExpressions() {
                 return tree.args;
             }
+            public void attribTree(Symbol constrSymbol, Type constrType) {
+                tree.constructor = constrSymbol;
+                tree.constructorType = constrType;
+            }
         });
     }
     
@@ -2085,6 +2090,9 @@
             public List<JCExpression> argumentExpressions() {
                 return null;
             }
+            public void attribTree(Symbol constrSymbol, Type constrType) {
+                //do nothing;
+            }
         });
     }
 
@@ -2113,14 +2121,14 @@
         //if the type of the instance creation expression is a class type
         //apply method resolution inference (JLS 15.12.2.7). The return type
         //of the resolved constructor will be a partially instantiated type
-        Symbol constructor = rs.resolveDiamond(tree.pos(),
+        Pair<Symbol, Symbol> constructorPair = rs.resolveDiamond(tree.pos(),
                     localEnv,
                     site,
                     argtypes,
                     typeargtypes);
 
         Type owntype = types.createErrorType(clazztype);
-        if (constructor.kind == MTH) {
+        if (constructorPair.fst.kind == MTH) {
             ResultInfo diamondResult = new ResultInfo(VAL, resultInfo.pt, new Check.NestedCheckContext(resultInfo.checkContext) {
                 @Override
                 public void report(DiagnosticPosition pos, JCDiagnostic details) {
@@ -2128,14 +2136,18 @@
                             diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", clazztype.tsym), details));
                 }
             });
-            owntype = checkMethod(site,
-                    constructor,
+            Type constructorType = checkMethod(site,
+                    constructorPair.fst,
                     diamondResult,
                     localEnv,
                     diamondHelper.argumentExpressions(),
                     argtypes,
                     typeargtypes,
-                    localEnv.info.varArgs).getReturnType();
+                    localEnv.info.varArgs);
+            owntype = constructorType.getReturnType();
+            if (!owntype.isErroneous()) {
+                diamondHelper.attribTree(constructorPair.snd, types.createMethodTypeWithReturn(constructorType, syms.voidType));
+            }
         }
 
         return chk.checkClassType(diamondHelper.pos(), owntype, true);
@@ -2297,9 +2309,9 @@
     //where
         private void checkAccessibleSAM(final DiagnosticPosition pos, final Env<AttrContext> env, final Infer.InferenceContext inferenceContext, final Type target) {
             if (inferenceContext.free(target)) {
-                inferenceContext.addPendingCheck(new Infer.PendingCheck() {
+                inferenceContext.addPendingCheck(new PendingCheck() {
                     public void eval() {
-                        checkAccessibleSAM(pos, env, inferenceContext, inferenceContext.asInstType(target));
+                        checkAccessibleSAM(pos, env, inferenceContext, inferenceContext.asInstType(target, types));
                     }
                 });
             } else {
@@ -2321,7 +2333,7 @@
             @Override
             public boolean compatible(Type found, Type req, Warner warn) {
                 //return type must be compatible in both current context and assignment context
-                return types.isAssignable(found, inferenceContext().asFree(req), warn) &&
+                return types.isAssignable(found, inferenceContext().asFree(req, types), warn) &&
                         super.compatible(found, req, warn);
             }
             @Override
@@ -2783,7 +2795,7 @@
      */
     void checkLambdaCompatible(JCLambda tree, Type target, CheckContext checkContext, boolean speculativeAttr) {
         Type descriptor = types.findDescriptor(target);
-        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
+        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
 
         //return values have already been checked - but if lambda has no return
         //values, we must ensure that void/value compatibility is correct;
@@ -2794,14 +2806,14 @@
             checkContext.report(tree, diags.fragment("infer.incompatible.ret.types.in.lambda",
                     diags.fragment("missing.ret.val", returnType)));
         }
-
-        List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes());
+        
+        List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes(), types);
         if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) {
             checkContext.report(tree, diags.fragment("infer.incompatible.arg.types.in.lambda"));
         }
 
         if (!speculativeAttr) {
-            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
+            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types);
             if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) {
                 log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes);
             }
@@ -2810,7 +2822,7 @@
     
     void checkReferenceCompatible(JCMemberReference tree, Type target, Type refType, CheckContext checkContext, boolean speculativeAttr) {
         Type descriptor = types.findDescriptor(target);
-        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
+        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
         
         Type resType = tree.getMode() == ReferenceMode.INVOKE ?
                 refType.getReturnType() : tree.expr.type;
@@ -2834,7 +2846,7 @@
         }
 
         if (!speculativeAttr) {
-            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
+            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types);
             if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) {
                 log.error(tree, "incompatible.thrown.types.in.lambda", refType.getThrownTypes());
             }
@@ -2855,7 +2867,7 @@
         }
 
         // Attribute the qualifier expression, and determine its symbol (if any).
-        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Infer.anyPoly));
+        Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.anyPoly));
         if ((pkind() & (PCK | TYP)) == 0)
             site = capture(site); // Capture field access
 
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Aug 03 12:48:20 2012 +0100
@@ -41,6 +41,7 @@
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.ANNOTATION;
@@ -100,7 +101,7 @@
         rs = Resolve.instance(context);
         syms = Symtab.instance(context);
         enter = Enter.instance(context);
-        infer = Infer.instance(context);
+        infer = InferFactory.instance(context).getInfer();
         this.types = Types.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         Options options = Options.instance(context);
@@ -519,9 +520,9 @@
     Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) {
         final Infer.InferenceContext inferenceContext = checkContext.inferenceContext();
         if (inferenceContext.free(req)) {
-            inferenceContext.addPendingCheck(new Infer.PendingCheck() {
+            inferenceContext.addPendingCheck(new PendingCheck() {
                 public void eval() {
-                    checkType(pos, found, inferenceContext.asInstType(req), checkContext);
+                    checkType(pos, found, inferenceContext.asInstType(req, types), checkContext);
                 }
             });
         }
--- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Fri Aug 03 12:48:20 2012 +0100
@@ -37,6 +37,9 @@
 
 import javax.tools.JavaFileObject;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import static com.sun.tools.javac.code.TypeTags.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
@@ -159,17 +162,31 @@
     /** array of deferred attribution modes */
     AttrRound[] attrRounds = {    
         new AttrRound(AttrMode.CHECK) {
-            public Type doAttr(DeferredType<?> dt, ResultInfo result) {
-                if (isStuck(dt, result)) {
-                    throw new StuckDeferredAttrException(result.checkContext.inferenceContext().inferenceVars());
+            public Type doAttr(final DeferredType<?> dt, ResultInfo result) {
+                List<Type> stuckVars = stuckVars(dt, result);
+                if (stuckVars.nonEmpty()) {
+                    throw new StuckDeferredAttrException(stuckVars);
+                }                
+                Type owntype = attr.attribTree(dt.tree, dt.env, result);
+                //the computed type might contain free variables
+                //which means the type should be recomputed after inference
+                //has completed
+                if (result.checkContext.inferenceContext().free(owntype)) {
+                    final Infer.InferenceContext inferenceContext = result.checkContext.inferenceContext();
+                    result.checkContext.inferenceContext().addPendingCheck(new Infer.InferenceContext.PendingCheck() {
+                        public void eval() {
+                            dt.qtype = inferenceContext.asInstType(dt.qtype, types);
+                        }
+                    });
                 }
-                return dt.qtype = attr.attribTree(dt.tree, dt.env, result);
+                return dt.qtype = owntype;
             }
         },
         new AttrRound(AttrMode.SPECULATIVE) {
             public Type doAttr(DeferredType<?> dt, ResultInfo result) {
-                if (isStuck(dt, result)) {
-                    throw new StuckDeferredAttrException(result.checkContext.inferenceContext().inferenceVars());
+                List<Type> stuckVars = stuckVars(dt, result);
+                if (stuckVars.nonEmpty()) {
+                    throw new StuckDeferredAttrException(stuckVars);
                 }
                 JCTree newTree = new TreeCopier<Object>(make).copy(dt.tree);
                 Env<AttrContext> speculativeEnv = dt.env.dup(newTree, dt.env.info.dup(dt.env.info.scope.dupUnshared()));
@@ -238,7 +255,7 @@
      * given expected context
      */
     Type attribDeferred(DeferredType<?> dt, AttrMode mode, final ResultInfo result) {
-        if (dt.qtype.tag != NONE) {
+        if (dt.qtype.tag != NONE && !result.checkContext.inferenceContext().free(dt.qtype)) {
             return result.check(dt.tree, dt.qtype);
         } else {
             for (AttrRound attrRound : attrRounds) {
@@ -255,10 +272,10 @@
      * Check as to whether a given deferred type can be type-checked using
      * given expected context
      */
-    boolean isStuck(DeferredType<?> dt, ResultInfo resultInfo) {
+    List<Type> stuckVars(DeferredType<?> dt, ResultInfo resultInfo) {
         StuckChecker sc = new StuckChecker(resultInfo);
         sc.scan(dt.tree);
-        return sc.stuck;
+        return List.from(sc.stuckVars);
     }
 
     /**
@@ -272,7 +289,7 @@
         Type pt;
         Filter<JCTree> treeFilter;
         Infer.InferenceContext inferenceContext;
-        boolean stuck = false;
+        Set<Type> stuckVars = new HashSet<Type>();
 
         final Filter<JCTree> argsFilter = new Filter<JCTree>() {
             public boolean accepts(JCTree t) {
@@ -306,13 +323,18 @@
             Type prevPt = pt;
             Filter<JCTree> prevFilter = treeFilter;
             try {
-                if ((stuck |= inferenceContext.inferenceVars().contains(pt)) ||
-                        !types.isSam(pt.tsym)) {
+                if (inferenceContext.inferenceVars().contains(pt)) {
+                    stuckVars.add(pt);
+                }
+                if (!types.isSam(pt.tsym)) {
                     return;
                 }
                 Type descType = types.findDescriptor(pt);
-                stuck |= !TreeInfo.isExplicitLambda(tree) &&
-                        Type.containsAny(descType.getParameterTypes(), inferenceContext.inferenceVars());
+                List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
+                if (!TreeInfo.isExplicitLambda(tree) &&
+                        freeArgVars.nonEmpty()) {
+                    stuckVars.addAll(freeArgVars);
+                }
                 pt = descType.getReturnType();
                 if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
                     scan(tree.getBody());
@@ -329,12 +351,16 @@
         @Override
         public void visitReference(JCMemberReference tree) {
             scan(tree.expr);
-            if ((stuck |= inferenceContext.inferenceVars().contains(pt)) ||
-                    !types.isSam(pt.tsym)) {
+            if (inferenceContext.inferenceVars().contains(pt)) {
+                stuckVars.add(pt);
+                return;
+            }
+            if (!types.isSam(pt.tsym)) {
                 return;
             }
             Type descType = types.findDescriptor(pt);
-            stuck |= Type.containsAny(descType.getParameterTypes(), inferenceContext.inferenceVars());
+            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
+            stuckVars.addAll(freeArgVars);
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.comp.GraphInfer.InferenceSolver.AcyclicInferenceGraph;
+import com.sun.tools.javac.comp.GraphInfer.InferenceSolver.AcyclicInferenceGraph.Node;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
+import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.sun.tools.javac.code.TypeTags.*;
+
+/** Helper class for type parameter inference, used by the attribution phase.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class GraphInfer extends Infer {
+
+    Check chk;
+    Resolve rs;
+    DeferredAttr deferredAttr;
+    Log log;
+
+    protected GraphInfer(Context context) {
+        super(context);
+        rs = Resolve.instance(context);
+        deferredAttr = DeferredAttr.instance(context);
+        log = Log.instance(context);
+        chk = Check.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
+    }
+    
+    @Override
+    public Type instantiateMethod(Env<AttrContext> env,
+                                  List<Type> tvars,
+                                  MethodType mt,
+                                  Symbol msym,
+                                  Attr.ResultInfo resultInfo,
+                                  List<Type> argtypes,
+                                  boolean allowBoxing,
+                                  boolean useVarargs,
+                                  Resolve.MethodResolutionContext resolveContext,
+                                  Warner warn) throws InferenceException {
+        //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
+        final GraphInferenceContext inferenceContext = new GraphInferenceContext(tvars);
+        
+        rs.checkRawArgumentsAcceptable(env, resolveContext.attrMode(), inferenceContext, argtypes, mt.getParameterTypes(),
+                allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
+        
+        if (resultInfo != null &&
+                !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
+            Type to = resultInfo.pt.tag == NONE ? mt.getReturnType() : resultInfo.pt;
+            Type qtype1 = inferenceContext.asFree(mt.getReturnType(), types);
+            if (!types.isSubtypeNoCapture(qtype1,
+                    qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to) &&
+                    !types.isSubtypeNoCapture(mt.getReturnType(), resultInfo.checkContext.inferenceContext().asFree(to, types))) {                
+                throw inferenceException
+                        .setMessage("infer.no.conforming.instance.exists",
+                        inferenceContext.restvars(), mt.getReturnType(), to);
+            }
+
+            if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
+                //propagate inference context outwards and exit
+                inferenceContext.dupTo(resultInfo.checkContext.inferenceContext());
+                return mt;
+            }
+        }
+
+        // minimize as yet undetermined type variables
+        inferenceContext.solve();
+
+        mt = (MethodType)inferenceContext.asInstType(mt, types);
+        
+        inferenceContext.finish();
+        
+        if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
+            log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
+        }
+        
+        // return instantiated version of method type
+        return mt;
+    }
+    
+    private void instantiateAsUninferredVars(List<Type> vars, InferenceContext inferenceContext) {
+        ListBuffer<Type> todo = ListBuffer.lb();
+        //step 1 - create fresh tvars
+        for (Type t : vars) {
+            UndetVar uv = (UndetVar)inferenceContext.asFree(t, types);
+            List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
+            if (Type.containsAny(upperBounds, vars)) {
+                TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
+                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
+                todo.append(uv);
+                uv.inst = fresh_tvar.type;
+            } else if (upperBounds.nonEmpty()) {
+                uv.inst = types.glb(upperBounds);
+            } else {
+                uv.inst = syms.objectType;
+            }
+        }
+        //step 2 - replace fresh tvars in their bounds
+        List<Type> formals = vars;
+        for (Type t : todo) {
+            UndetVar uv = (UndetVar)t;
+            TypeVar ct = (TypeVar)uv.inst;
+            ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
+            if (ct.bound.isErroneous()) {
+                //report inference error if glb fails
+                reportBoundError(uv, BoundErrorKind.BAD_UPPER);
+            }
+            formals = formals.tail;
+        }     
+    }
+
+    /**
+     * Check bounds and perform incorporation
+     */
+    void checkWithinBounds(InferenceContext inferenceContext, Warner warn) throws InferenceException {
+        super.checkWithinBounds(inferenceContext, warn, incorporationSteps);
+    }
+    //where
+    IncorporationStep[] incorporationSteps = {
+        //cross pollination of bounds --- if an undet-variable contains i.e. bounds
+        //of the kind alpha <: List<gamma> && alpha :> ArrayList<beta>, we
+        //do ArrayList<gamma> <: List<beta> and derive gamma == beta.
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {                
+                for (Type b1 : uv.getBounds(InferenceBound.UPPER)) {
+                    for (Type b2 : uv.getBounds(InferenceBound.LOWER)) {
+                        if (!inferenceContext.inferenceVars().contains(b1) &&
+                                !inferenceContext.inferenceVars().contains(b2) &&
+                                types.asSuper(b2, b1.tsym) != null) {
+                            types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types));
+                        }
+                    }
+                }
+            }
+        },
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {
+                for (Type b1 : uv.getBounds(InferenceBound.UPPER)) {
+                    for (Type b2 : uv.getBounds(InferenceBound.EQ)) {
+                        if (!inferenceContext.inferenceVars().contains(b1) &&
+                                !inferenceContext.inferenceVars().contains(b2) &&
+                                types.asSuper(b2, b1.tsym) != null) {
+                            types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types));
+                        }
+                    }
+                }
+            }
+        },
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {
+                for (Type b1 : uv.getBounds(InferenceBound.EQ)) {
+                    for (Type b2 : uv.getBounds(InferenceBound.LOWER)) {
+                        if (!inferenceContext.inferenceVars().contains(b1) &&
+                                !inferenceContext.inferenceVars().contains(b2) &&
+                                types.asSuper(b2, b1.tsym) != null) {
+                            types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types));
+                        }
+                    }
+                }
+            }
+        },
+        //cross pollination of bounds --- propagate upper/lower bounds
+        //in constraints of the kind alpha <: beta, alpha :> beta, alpha == beta
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {
+                for (Type b : uv.getBounds(InferenceBound.UPPER)) {
+                    if (inferenceContext.inferenceVars().contains(b)) {
+                        UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types);
+                        //alpha <: beta
+                        //1. copy alpha's lower to beta's
+                        for (Type l : uv.getBounds(InferenceBound.LOWER)) {
+                            uv2.addBound(InferenceBound.LOWER, l, types);
+                        }
+                        //2. copy beta's upper to alpha's
+                        for (Type u : uv2.getBounds(InferenceBound.UPPER)) {
+                            uv.addBound(InferenceBound.UPPER, u, types);
+                        }
+                    }
+                }
+            }
+        },
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {
+                for (Type b : uv.getBounds(InferenceBound.LOWER)) {
+                    if (inferenceContext.inferenceVars().contains(b)) {
+                        UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types);
+                        //alpha :> beta
+                        //1. copy alpha's upper to beta's
+                        for (Type u : uv.getBounds(InferenceBound.UPPER)) {
+                            uv2.addBound(InferenceBound.UPPER, u, types);
+                        }
+                        //2. copy beta's lower to alpha's
+                        for (Type l : uv2.getBounds(InferenceBound.LOWER)) {
+                            uv.addBound(InferenceBound.UPPER, l, types);
+                        }
+                    }
+                }
+            }
+        },
+        new IncorporationStep() {
+            public void apply(UndetVar uv, InferenceContext inferenceContext) {
+                for (Type b : uv.getBounds(InferenceBound.EQ)) {
+                    if (inferenceContext.inferenceVars().contains(b)) {
+                        UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types);
+                        //alpha == beta
+                        //1. copy all alpha's bounds to beta's
+                        for (InferenceBound ib : InferenceBound.values()) {
+                            for (Type b2 : uv.getBounds(ib)) {
+                                uv2.addBound(ib, b2, types);
+                            }
+                        }
+                        //2. copy all beta's bounds to alpha's
+                        for (InferenceBound ib : InferenceBound.values()) {
+                            for (Type b2 : uv2.getBounds(ib)) {
+                                uv.addBound(ib, b2, types);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    };
+ 
+    // <editor-fold desc="SAM type instantiation">
+    @Override
+    public Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) {
+        if (types.capture(samType) == samType) {
+            //if capture doesn't change the type then return the target unchanged
+            //(this means the target contains no wilddcards!)
+            return samType;
+        } else {
+            List<Type> tvars = types.newInstances(samType.tsym.type.getTypeArguments());
+            Type formalSam = types.subst(samType.tsym.type, samType.tsym.type.getTypeArguments(), tvars);
+            GraphInferenceContext samInferenceContext = new GraphInferenceContext(tvars);
+            if (paramTypes != null) {
+                //get constraints from explicit params (this is done by
+                //checking that explicit param types are equal to the ones
+                //in the SAM descriptors)
+                List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes();
+                if (descParameterTypes.size() != paramTypes.size()) {
+                    checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                    return types.createErrorType(samType);
+                }
+                for (Type p : descParameterTypes) {
+                    if (!types.isSameType(samInferenceContext.asFree(p, types), paramTypes.head)) {
+                        checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                        return types.createErrorType(samType);
+                    }
+                    paramTypes = paramTypes.tail;
+                }
+            }
+            //propagate constraints on wildcards
+            if (!types.isSubtypeUnchecked(samInferenceContext.asFree(formalSam, types), samType)) {
+                checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                return types.createErrorType(samType);
+            }
+            
+            if (!checkContext.inferenceContext().free(samType)) {
+                //since there are no inference variable in the target type
+                //we can immediately solve the inference context
+                try {
+                    samInferenceContext.solve();
+                    return samInferenceContext.asInstType(formalSam, types);
+                } catch (InferenceException ex) {
+                    checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                    return types.createErrorType(samType);
+                }
+            } else {
+                //if the target type depends on one or more inference variables
+                //we need to propagate the wildcards inference context onto
+                //the enclosing inference context [only if lambda has implicit parameters]
+                if (paramTypes == null) {
+                    try {
+                        //we need to fix synthetic inference variables in argument position
+                        samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptor(formalSam).getParameterTypes()));
+                    } catch (InferenceException ex) {
+                        checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                        return types.createErrorType(samType);
+                    }
+                }
+                if (samInferenceContext.restvars().nonEmpty()) {
+                    samInferenceContext.dupTo(checkContext.inferenceContext());
+                }
+                return samInferenceContext.asInstType(formalSam, types);
+            }
+        }
+    }
+    // </editor-fold>
+    
+    /**
+     * Inference strategy - act as an input to the inference solver; a strategy is
+     * composed of two ingredients: (i) find a node to solve in the inference graph,
+     * and (ii) tell th engine when we are done fixing inference variables
+     */
+    interface SolverStrategy {
+        /**
+         * Pick the next node (leaf) to solve in th graph
+         */
+        Node pickNode(AcyclicInferenceGraph g);
+        /**
+         * Is this the last step?
+         */
+        boolean done();
+    }
+    
+    /**
+     * Simple solver strategy class that locates all leaves inside a graph
+     * and picks the first leaf as the next node to solve
+     */
+    abstract class LeafSolver implements SolverStrategy {
+        
+        protected ArrayList<Node> leaves(AcyclicInferenceGraph g) {
+            //pick the first node with no outgoing edges (= no dependencies)
+            ArrayList<Node> leaves = new ArrayList<Node>();
+            for (Node n : g.nodes) {
+                if (!g.graph_deps.containsKey(n)) {
+                    leaves.add(n);
+                }
+            }
+            return leaves;
+        }
+        
+        public Node pickNode(AcyclicInferenceGraph g) {
+            ArrayList<Node> leaves = leaves(g);
+            Assert.check(!leaves.isEmpty(), "no nodes to solve!");
+            return leaves.get(0);
+        }
+    }
+    
+    /**
+     * This solver uses an heuristic to pick the best leaf - the heuristic
+     * tries to select the node that has maximal probability to contain one
+     * or more inference variables in a given list
+     */
+    abstract class BestLeafSolver extends LeafSolver {
+        
+        List<Type> varsToSolve;
+
+        BestLeafSolver(List<Type> varsToSolve) {
+            this.varsToSolve = varsToSolve;
+        }
+        
+        public Node pickNode(final AcyclicInferenceGraph g) {
+            //pick the first node with no outgoing edges (= no dependencies)
+            ArrayList<Node> leaves = super.leaves(g);
+            Assert.check(!leaves.isEmpty(), "no nodes to solve!");
+            Comparator<Node> cnode = new Comparator<Node>() {
+                int varsCount(Node n) {
+                    int count = 0;
+                    for (Type t : n.node_vars) {
+                        if (t.containsAny(varsToSolve)) {
+                            //does this node contain any stuck vars?
+                            count++;
+                        }
+                        for (Node n2 : g.nodes) {
+                            if (n2.edgeTo(n)) {
+                                //does any dependant node contains any stuck vars?
+                                count += varsCount(n2);
+                            }
+                        }
+                    }
+                    return count;
+                }
+
+                public int compare(Node o1, Node o2) {
+                    return varsCount(o2) - varsCount(o1);
+                }
+            };
+            Collections.sort(leaves, cnode);
+            return leaves.get(0);
+        }
+    }
+    
+    /**
+     * Stateful inference context - state of the context can be saved/restore
+     * (this feature is used by the JDK 8 inference engine); on-demand inference
+     * variable solving is addressed by instantiating at least one variable using
+     * an heuristic to find the best path in the inference graph
+     */
+    class GraphInferenceContext extends Infer.InferenceContext {        
+        
+        /** backed up inference variables */
+        List<Type> saved_undet;
+        
+        GraphInferenceContext(List<Type> inferenceVars) {
+            super(inferenceVars, types);
+        }
+        
+        /**
+         * Save the state of this inference context
+         */
+        void save() {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            for (Type t : undetvars) {
+                UndetVar uv = (UndetVar)t;
+                UndetVar uv2 = new UndetVar((TypeVar)uv.qtype, true, types);
+                for (InferenceBound ib : InferenceBound.values()) {
+                    for (Type b : uv.getBounds(ib)) {
+                        uv2.addBound(ib, b, types);
+                    }
+                }
+                uv2.inst = uv.inst;
+                buf.add(uv2);
+            }
+            saved_undet = buf.toList();
+        }
+        
+        /**
+         * Restore the state of this inference context to the previous known checkpoint
+         */
+        void rollback() {
+            Assert.check(saved_undet != null && saved_undet.length() == undetvars.length());
+            undetvars = saved_undet;
+            saved_undet = null;
+        }
+        
+        /**
+         * Copy variable in this inference context to the given context
+         */
+        void dupTo(InferenceContext that) {
+            that.undetvars = that.undetvars.appendList(undetvars);
+            that.pendingChecks = that.pendingChecks.appendList(pendingChecks);
+        }
+        
+        private void solve(SolverStrategy ss) {
+            InferenceSolver s = new InferenceSolver(this);
+            s.solve(ss);
+        }
+        
+        /**
+         * solve all variables in this context
+         */
+        public void solve() {
+            solve(new LeafSolver() {
+                public boolean done() {
+                    return restvars().isEmpty();
+                }
+            });
+        }
+        
+        /**
+         * solve all variables in the given list
+         */
+        public void solve(final List<Type> vars) {
+            solve(new BestLeafSolver(vars) {
+                public boolean done() {
+                    return !free(asInstTypes(vars, types));
+                }
+            });
+        }
+
+        @Override
+        public void solveAny(final List<Type> stuckvars) {
+            solve(new BestLeafSolver(stuckvars) {
+                public boolean done() {
+                    return asInstTypes(stuckvars, types) != stuckvars;
+                }
+            });
+        }
+    }
+    
+    /**
+     * This is the inference solver - the solver organizes all inference variables in
+     * a given inference context by bound dependencies - in the general case, such dependencies
+     * would lead to a cyclic directed graph; the dependency info is used to build
+     * an acyclic graph, where all cyclic variables are bundled together. An inference
+     * step corresponds to solving a node in the acyclic graph - this is done by
+     * relying on a given strategy (see SolverStrategy).
+     */
+    class InferenceSolver {
+        /**
+         * There are two kind of inference strategies: (i) lower bounds can be used to
+         * infer a type using lub, alternatively (ii) upper bounds can be used to
+         * infer a type using glb.
+         */
+        abstract class InferenceStep implements Filter<UndetVar> {
+
+            InferenceBound ib;
+
+            public InferenceStep(InferenceBound ib) {
+                this.ib = ib;
+            }
+
+            abstract Type solve(UndetVar uv);
+
+            boolean exact(UndetVar uv) {
+                return uv.getBounds(ib).length() == filterBounds(uv).length();
+            }
+
+            public boolean accepts(UndetVar t) {
+                return filterBounds(t).nonEmpty();
+            }
+
+            List<Type> filterBounds(UndetVar uv) {
+                return Type.filter(uv.getBounds(ib), new Filter<Type>() {
+                        public boolean accepts(Type t) {
+                            return !t.containsAny(inferenceContext.inferenceVars());
+                        }
+                });
+            }
+        }
+
+        /** eq bound inference */
+        InferenceStep eq = new InferenceStep(InferenceBound.EQ) {
+            @Override
+            Type solve(UndetVar uv) {
+                return filterBounds(uv).head;
+            }
+        };
+
+        /** lower bound inference */
+        InferenceStep lower = new InferenceStep(InferenceBound.LOWER) {
+            @Override
+            Type solve(UndetVar uv) {
+                List<Type> lobounds = filterBounds(uv);
+                Type owntype = types.lub(lobounds);
+                if (owntype.tag == ERROR) {
+                    throw inferenceException
+                        .setMessage("no.unique.minimal.instance.exists",
+                                    uv.qtype, lobounds);
+                } else {
+                    return owntype;
+                }
+            }
+        };
+
+        /** upper bound inference */
+        InferenceStep upper = new InferenceStep(InferenceBound.UPPER) {
+            @Override
+            Type solve(UndetVar uv) {
+                List<Type> hibounds = filterBounds(uv);
+                Type owntype = types.glb(hibounds);
+                if (owntype.isErroneous()) {
+                    throw inferenceException
+                        .setMessage("no.unique.maximal.instance.exists",
+                                    uv.qtype, hibounds);
+                } else {
+                    return owntype;
+                }
+            }
+        };
+
+        /** inference steps - steps are ordered by priority; first, only eq bounds
+         * are considered; then eq and lower bound (corresponding roughly to old 15.12.2.7)
+         * then all bounds are considered.
+         */
+        InferenceStep[][] phases = { { eq }, { eq, lower }, { eq, lower, upper } };
+
+        Map<Type, List<Type>> deps;
+        GraphInferenceContext inferenceContext;
+
+        InferenceSolver(GraphInferenceContext inferenceContext) {
+            this.inferenceContext = inferenceContext;
+            computeDependencies();            
+        }
+
+        private void computeDependencies() {
+            deps = new HashMap<Type, List<Type>>();
+            for (Type i : inferenceContext.restvars()) {
+                for (Type j : inferenceContext.restvars()) {
+                    UndetVar uv_i = (UndetVar)inferenceContext.asFree(i, types);
+                    if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) {
+                        //update i's deps
+                        List<Type> depVars_i = deps.get(i);
+                        if (depVars_i == null) {
+                            depVars_i = List.nil();                                
+                        }
+                        depVars_i = depVars_i.prepend(j);
+                        deps.put(i, depVars_i);
+                        //update j's deps - only if i's bounds contain _exactly_ j
+                        if (uv_i.getBounds(InferenceBound.values()).contains(j)) {                        
+                            List<Type> depVars_j = deps.get(j);
+                            if (depVars_j == null) {
+                                depVars_j = List.nil();                                    
+                            }
+                            depVars_j = depVars_j.prepend(i);
+                            deps.put(j, depVars_j);
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Solve variables in a given inference context. The amount of variables
+         * to be solved, and the way in which the underlying acyclic graph is explored
+         * depends on the selected solver strategy.
+         */
+        void solve(SolverStrategy sstrategy) {
+            checkWithinBounds(inferenceContext, Warner.noWarnings); //initial propagation of bounds
+            while (!sstrategy.done()) {
+                List<Type> varsToSolve = sstrategy.pickNode(new AcyclicInferenceGraph()).node_vars;
+                inferenceContext.save();
+                boolean exact = true;
+                //repeat until all variables are solved
+                while (Type.containsAny(inferenceContext.restvars(), varsToSolve)) {
+                    boolean stuck = true;
+                    //for each inference phase
+                    for (InferenceStep[] phase : phases) {
+                        //for each variable...
+                        for (Type i : varsToSolve) {
+                            //skip instantiated vars
+                            UndetVar uv_i = (UndetVar)inferenceContext.asFree(i, types);
+                            if (uv_i.inst != null) continue;
+                            //try to instantiate using one of the steps allowed in this phase
+                            for (InferenceStep step : phase) {
+                                if (step.accepts(uv_i)) {
+                                    uv_i.inst = step.solve(uv_i);
+                                    exact = exact && step.exact(uv_i);
+                                    stuck = false;
+                                }
+                            }
+                        }
+                        if (!stuck) {
+                            try {
+                                checkWithinBounds(inferenceContext, Warner.noWarnings);
+                            } catch (InferenceException ex) {
+                                if (exact) {
+                                    throw ex;
+                                } else {
+                                    inferenceContext.rollback();
+                                    instantiateAsUninferredVars(varsToSolve, inferenceContext);
+                                    checkWithinBounds(inferenceContext, Warner.noWarnings);
+                                }
+                            }
+                            break;
+                        }
+                    }
+                    if (stuck) {
+                        inferenceContext.rollback();
+                        instantiateAsUninferredVars(varsToSolve, inferenceContext);
+                        checkWithinBounds(inferenceContext, Warner.noWarnings);
+                    }
+                }
+            }
+        }
+        
+        /**
+         * Debugging: dump a string containing a dot representation of the bound
+         * dependencies in this solver.
+         */
+        String toDot() {
+            StringBuilder buf = new StringBuilder();
+            buf.append(String.format("digraph %s {\n", hashCode()));
+            buf.append("label = \"Inference variables:\\n");
+            for (Type t : inferenceContext.undetvars) {
+                UndetVar uv = (UndetVar)t;
+                buf.append(String.format("var %s - upper bounds = %s, lower bounds = %s, eq bounds = %s\\n",
+                        uv.qtype, uv.getBounds(InferenceBound.UPPER), uv.getBounds(InferenceBound.LOWER), uv.getBounds(InferenceBound.EQ)));
+            }
+            buf.append("\";\n");
+            //dump nodes
+            for (Type iv : inferenceContext.inferenceVars()) {
+                buf.append(String.format("%s [label = \"%s\"];\n", iv.hashCode(), iv.tsym.name));
+            }
+            //dump arcs
+            for (Map.Entry<Type, List<Type>> entry : deps.entrySet()) {
+                Type from = entry.getKey();
+                for (Type to : entry.getValue()) {                    
+                    StringBuilder buf2 = new StringBuilder();
+                    String sep = "";                    
+                    for (Type t : ((UndetVar)inferenceContext.asFree(from, types)).getBounds(InferenceBound.UPPER, InferenceBound.LOWER, InferenceBound.EQ)) {
+                        if (t.contains(to)) {
+                            buf2.append(sep);
+                            buf2.append(t);
+                            sep = ",";
+                        }
+                    }                    
+                    buf.append(String.format("%s -> %s [label = \" %s \"];\n", from.hashCode(), to.hashCode(), buf2));
+                }
+            }
+            buf.append("}\n");
+            return buf.toString();
+        }
+
+        /**
+         * The acyclic reduction of the directed (possibly cyclic) graph
+         * computed by this solver. Each node in this graph contains one
+         * or more (in case of bound cycles) inference variables.
+         */
+        class AcyclicInferenceGraph {
+            
+            class Node {
+                List<Type> node_vars;
+
+                Node(List<Type> node_vars) {
+                    this.node_vars = node_vars;
+                }
+
+                public boolean edgeTo(Node node) {
+                    for (Type i : node_vars) {
+                        for (Type j : node.node_vars) {
+                            //skip edges that point to same super-node
+                            if (node_vars.contains(j)) continue;
+                            List<Type> depVars = deps.get(i);
+                            if (depVars != null && depVars.contains(j)) {
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                }
+            }
+            
+            List<Node> nodes;
+            Map<Node, List<Node>> graph_deps;
+
+            AcyclicInferenceGraph() {
+                nodes = findNodes();
+                computeDependencies();
+            }
+
+            private Set<Set<Type>> findCycles() {
+                Set<Set<Type>> cycles = new HashSet<Set<Type>>();
+                for (Type iv : inferenceContext.restvars()) {
+                    findCycles(iv, iv, new ArrayList<Type>(), cycles);
+                }
+                Set<Set<Type>> maxCycles = new HashSet<Set<Type>>(cycles);
+                while (mergeCycles(cycles, maxCycles)) {
+                    cycles = maxCycles;
+                    maxCycles = new HashSet<Set<Type>>(cycles);
+                }
+                return maxCycles;
+            }
+
+            private boolean mergeCycles(Set<Set<Type>> cycles, Set<Set<Type>> maxCycles) {
+                //merge overlapping cycles
+                for (Set<Type> cycle1 : cycles) {
+                    for (Set<Type> cycle2 : cycles) {
+                        if (cycle1 == cycle2) continue;
+                        for (Type t : cycle1) {
+                            if (cycle2.contains(t)) {
+                                maxCycles.remove(cycle1);
+                                maxCycles.remove(cycle2);
+                                Set<Type> cycle3 = new HashSet<Type>(cycle1);
+                                cycle3.addAll(cycle2);
+                                maxCycles.add(cycle3);
+                                return true;
+                            }
+                        }
+                    }
+                }
+                return false;
+            }
+
+            private void findCycles(Type start, Type current, ArrayList<Type> path, Set<Set<Type>> cycles) {
+                //System.out.printf("find cycles - start = %s, current = %s, path = %s, cycles = %s\n" , start, current, path, cycles);        
+                if (current == start && !path.isEmpty()) {            
+                    cycles.add(new HashSet<Type>(path));
+                } else if (path.contains(current)) {
+                    return;
+                } else {
+                    path.add(current);
+                    List<Type> depVars = deps.get(current);
+                    if (depVars != null) {
+                        for (Type iv : depVars) {                    
+                            findCycles(start, iv, path, cycles);
+                        }
+                    }
+                    path.remove(current);
+                }
+            }
+
+            private List<Node> findNodes() {
+                Set<Set<Type>> cycles = findCycles();
+                List<Node> nodes = List.nil();
+                for (Set<Type> cycle : cycles) {
+                    nodes = nodes.prepend(new Node(List.from(cycle.toArray(new Type[cycle.size()]))));
+                }
+
+                for (Type iv : inferenceContext.restvars()) {
+                    boolean found = false;
+                    for (Set<Type> cycle : cycles) {
+                        if (cycle.contains(iv)) {
+                            found = true;
+                        }
+                    }
+                    if (!found) {
+                        nodes = nodes.prepend(new Node(List.of(iv)));
+                    }
+                }
+                return nodes;
+            }
+
+            private void computeDependencies() {
+                graph_deps = new HashMap<Node, List<Node>>();
+                for (Node i : nodes) {
+                    for (Node j : nodes) {
+                        if (i.edgeTo(j)) {
+                            //update i's deps
+                            List<Node> depNodes_i = graph_deps.get(i);
+                            if (depNodes_i == null) {
+                                depNodes_i = List.nil();
+                            }
+                            depNodes_i = depNodes_i.prepend(j);
+                            graph_deps.put(i, depNodes_i);
+                        }
+                    }
+                }
+            }
+            
+            /**
+             * Debugging: dot representation of this graph
+             */
+            String toDot() {
+                StringBuilder buf = new StringBuilder();
+                buf.append(String.format("digraph %s {\n", hashCode()));
+                //dump nodes
+                for (Node n : nodes) {
+                    buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.node_vars));
+                }
+                //dump arcs
+                for (Map.Entry<Node, List<Node>> entry : graph_deps.entrySet()) {
+                    Node from = entry.getKey();
+                    for (Node to : entry.getValue()) {
+                        StringBuilder buf2 = new StringBuilder();
+                        String sep = "";
+                        for (Type from2 : from.node_vars) {
+                            for (Type t : ((UndetVar)inferenceContext.asFree(from2, types)).getBounds(InferenceBound.UPPER, InferenceBound.LOWER, InferenceBound.EQ)) {
+                                if (t.containsAny(to.node_vars)) {
+                                    buf2.append(sep);
+                                    buf2.append(t);
+                                    sep = ",";
+                                }
+                            }
+                        }                    
+                        buf.append(String.format("%s -> %s [label = \" %s \"];\n", from.hashCode(), to.hashCode(), buf2));
+                    }
+                }
+                buf.append("}\n");
+                return buf.toString();
+            }
+        }
+    }
+}
--- a/src/share/classes/com/sun/tools/javac/comp/Infer.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Aug 03 12:48:20 2012 +0100
@@ -29,16 +29,16 @@
 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
-import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
-import java.util.Arrays;
-import java.util.EnumSet;
+import java.util.Set;
+
 import static com.sun.tools.javac.code.TypeTags.*;
 
 /** Helper class for type parameter inference, used by the attribution phase.
@@ -48,46 +48,19 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class Infer {
-    protected static final Context.Key<Infer> inferKey =
-        new Context.Key<Infer>();
-
-    /** A value for prototypes that admit any type, including polymorphic ones. */
-    public static final Type anyPoly = new Type(NONE, null);
+public abstract class Infer {
 
+    DeferredAttr deferredAttr;
     Symtab syms;
-    Types types;
-    Check chk;
-    Resolve rs;
-    DeferredAttr deferredAttr;
-    Log log;
+    Types types;    
     JCDiagnostic.Factory diags;
 
-    public static Infer instance(Context context) {
-        Infer instance = context.get(inferKey);
-        if (instance == null)
-            instance = new Infer(context);
-        return instance;
-    }
-
     protected Infer(Context context) {
-        context.put(inferKey, this);
+        deferredAttr = DeferredAttr.instance(context);
         syms = Symtab.instance(context);
         types = Types.instance(context);
-        rs = Resolve.instance(context);
-        deferredAttr = DeferredAttr.instance(context);
-        log = Log.instance(context);
-        chk = Check.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
-        ambiguousNoInstanceException =
-            new NoInstanceException(true, diags);
-        unambiguousNoInstanceException =
-            new NoInstanceException(false, diags);
-        invalidInstanceException =
-            new InvalidInstanceException(diags);
-        cyclicInferenceException =
-            new CyclicInferenceException(diags);
-
+        inferenceException = new InferenceException(diags);
     }
 
     public static class InferenceException extends InapplicableMethodException {
@@ -98,282 +71,14 @@
         }
     }
 
-    public static class NoInstanceException extends InferenceException {
-        private static final long serialVersionUID = 1;
-
-        boolean isAmbiguous; // exist several incomparable best instances?
-
-        NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) {
-            super(diags);
-            this.isAmbiguous = isAmbiguous;
-        }
-    }
-
-    public static class InvalidInstanceException extends InferenceException {
-        private static final long serialVersionUID = 2;
-
-        InvalidInstanceException(JCDiagnostic.Factory diags) {
-            super(diags);
-        }
-    }
-
-    public static class CyclicInferenceException extends InferenceException {
-        private static final long serialVersionUID = 3;
-
-        CyclicInferenceException(JCDiagnostic.Factory diags) {
-            super(diags);
-        }
-    }
-
-    private final NoInstanceException ambiguousNoInstanceException;
-    private final NoInstanceException unambiguousNoInstanceException;
-    private final InvalidInstanceException invalidInstanceException;
-    final CyclicInferenceException cyclicInferenceException;
-
-/***************************************************************************
- * Auxiliary type values and classes
- ***************************************************************************/
-
-    /** A mapping that turns type variables into undetermined type variables.
-     */
-    Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
-            public Type apply(Type t) {
-                if (t.tag == TYPEVAR) return new UndetVar(t);
-                else return t.map(this);
-            }
-        };
-
-    /** A mapping that returns its type argument with every UndetVar replaced
-     *  by its `inst' field. Throws a NoInstanceException
-     *  if this not possible because an `inst' field is null.
-     *  Note: mutually referring undertvars will be left uninstantiated
-     *  (that is, they will be replaced by the underlying type-variable).
-     */
-
-    Mapping getInstFun = new Mapping("getInstFun") {
-            public Type apply(Type t) {
-                switch (t.tag) {
-                    case UNKNOWN:
-                        throw ambiguousNoInstanceException
-                            .setMessage("undetermined.type");
-                    case UNDETVAR:
-                        UndetVar that = (UndetVar) t;
-                        if (that.inst == null)
-                            throw ambiguousNoInstanceException
-                                .setMessage("type.variable.has.undetermined.type",
-                                            that.qtype);
-                        return isConstraintCyclic(that) ?
-                            that.qtype :
-                            apply(that.inst);
-                        default:
-                            return t.map(this);
-                }
-            }
-
-            private boolean isConstraintCyclic(UndetVar uv) {
-                Types.UnaryVisitor<Boolean> constraintScanner =
-                        new Types.UnaryVisitor<Boolean>() {
-
-                    List<Type> seen = List.nil();
-
-                    Boolean visit(List<Type> ts) {
-                        for (Type t : ts) {
-                            if (visit(t)) return true;
-                        }
-                        return false;
-                    }
-
-                    public Boolean visitType(Type t, Void ignored) {
-                        return false;
-                    }
-
-                    @Override
-                    public Boolean visitClassType(ClassType t, Void ignored) {
-                        if (t.isCompound()) {
-                            return visit(types.supertype(t)) ||
-                                    visit(types.interfaces(t));
-                        } else {
-                            return visit(t.getTypeArguments());
-                        }
-                    }
-                    @Override
-                    public Boolean visitWildcardType(WildcardType t, Void ignored) {
-                        return visit(t.type);
-                    }
-
-                    @Override
-                    public Boolean visitUndetVar(UndetVar t, Void ignored) {
-                        if (seen.contains(t)) {
-                            return true;
-                        } else {
-                            seen = seen.prepend(t);
-                            return visit(t.inst);
-                        }
-                    }
-                };
-                return constraintScanner.visit(uv);
-            }
-        };
-
-/***************************************************************************
- * Mini/Maximization of UndetVars
- ***************************************************************************/
-
-    /** Instantiate undetermined type variable to its minimal upper bound.
-     *  Throw a NoInstanceException if this not possible.
+    protected final InferenceException inferenceException;
+    
+    // <editor-fold defaultstate="collapsed" desc="generic method type-inference">
+    /**
+     * Main inference entry point - instantiate a generic method type
+     * using given argument types and (possibly) an expected target-type.
      */
-    void maximizeInst(UndetVar that, Warner warn) throws NoInstanceException {
-        List<Type> hibounds = Type.filter(that.hibounds, errorFilter);
-        if (that.inst == null) {
-            if (hibounds.isEmpty())
-                that.inst = syms.objectType;
-            else if (hibounds.tail.isEmpty())
-                that.inst = hibounds.head;
-            else
-                that.inst = types.glb(hibounds);
-        }
-        if (that.inst == null ||
-            that.inst.isErroneous())
-            throw ambiguousNoInstanceException
-                .setMessage("no.unique.maximal.instance.exists",
-                            that.qtype, hibounds);
-    }
-    //where
-        private boolean isSubClass(Type t, final List<Type> ts) {
-            t = t.baseType();
-            if (t.tag == TYPEVAR) {
-                List<Type> bounds = types.getBounds((TypeVar)t);
-                for (Type s : ts) {
-                    if (!types.isSameType(t, s.baseType())) {
-                        for (Type bound : bounds) {
-                            if (!isSubClass(bound, List.of(s.baseType())))
-                                return false;
-                        }
-                    }
-                }
-            } else {
-                for (Type s : ts) {
-                    if (!t.tsym.isSubClass(s.baseType().tsym, types))
-                        return false;
-                }
-            }
-            return true;
-        }
-
-    private Filter<Type> errorFilter = new Filter<Type>() {
-        @Override
-        public boolean accepts(Type t) {
-            return !t.isErroneous();
-        }
-    };
-
-    /** Instantiate undetermined type variable to the lub of all its lower bounds.
-     *  Throw a NoInstanceException if this not possible.
-     */
-    void minimizeInst(UndetVar that, Warner warn) throws NoInstanceException {
-        List<Type> lobounds = Type.filter(that.lobounds, errorFilter);
-        if (that.inst == null) {
-            if (lobounds.isEmpty())
-                that.inst = syms.botType;
-            else if (lobounds.tail.isEmpty())
-                that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
-            else {
-                that.inst = types.lub(lobounds);
-            }
-            if (that.inst == null || that.inst.tag == ERROR)
-                    throw ambiguousNoInstanceException
-                        .setMessage("no.unique.minimal.instance.exists",
-                                    that.qtype, lobounds);
-            // VGJ: sort of inlined maximizeInst() below.  Adding
-            // bounds can cause lobounds that are above hibounds.
-            List<Type> hibounds = Type.filter(that.hibounds, errorFilter);
-            Type hb = null;
-            if (hibounds.isEmpty())
-                hb = syms.objectType;
-            else if (hibounds.tail.isEmpty())
-                hb = hibounds.head;
-            else
-                hb = types.glb(hibounds);
-            if (hb == null ||
-                hb.isErroneous())
-                throw ambiguousNoInstanceException
-                        .setMessage("incompatible.upper.bounds",
-                                    that.qtype, hibounds);
-        }
-    }
-
-/***************************************************************************
- * Exported Methods
- ***************************************************************************/
-
-    /** 
-     * Instantiate uninferred inference variables (JLS 15.12.2.8). First
-     * if the method return type is non-void, we derive constraints from the
-     * expected type - then we use declared bound well-formedness to derive additional
-     * constraints. If no instantiation exists, or if several incomparable
-     * best instantiations exist throw a NoInstanceException.
-     */
-    public void instantiateUninferred(DiagnosticPosition pos,
-            InferenceContext inferenceContext,
-            MethodType mtype,
-            Attr.ResultInfo resultInfo,
-            Warner warn) throws InferenceException {
-        for (List<Type> l = inferenceContext.undetvars; l.nonEmpty(); l = l.tail) {
-            UndetVar uv = (UndetVar)l.head;
-            uv.hibounds = uv.hibounds.appendList(inferenceContext.asFree(types.getBounds((TypeVar)uv.qtype)));
-        }
-        Type to = resultInfo.pt;
-        if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
-            to = mtype.getReturnType().tag <= VOID ?
-            mtype.getReturnType() : syms.objectType;
-        }
-        Type qtype1 = inferenceContext.asFree(mtype.getReturnType());
-        if (!types.isSubtype(qtype1,
-                qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
-            throw unambiguousNoInstanceException
-                    .setMessage("infer.no.conforming.instance.exists",
-                    inferenceContext.restvars(), mtype.getReturnType(), to);
-        }
-        inferenceContext.instantiate(warn, false, EnumSet.of(InferenceKind.UPPER));
-        
-        // System.out.println(" = " + qtype1.map(getInstFun));//DEBUG
-
-        List<Type> targs = Type.map(inferenceContext.undetvars, getInstFun);
-        if (Type.containsAny(targs, inferenceContext.inferenceVars())) {
-            //replace uninferred type-vars
-            targs = types.subst(targs,
-                    inferenceContext.inferenceVars(),
-                    instantiateAsUninferredVars(inferenceContext.undetvars, inferenceContext.inferenceVars()));
-        }
-        inferenceContext.insttypes = targs;
-    }
-    //where
-    private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) {
-        Assert.check(undetvars.length() == tvars.length());
-        ListBuffer<Type> new_targs = ListBuffer.lb();
-        //step 1 - create synthetic captured vars
-        for (Type t : undetvars) {
-            UndetVar uv = (UndetVar)t;
-            Type newArg = new CapturedType(t.tsym.name, t.tsym, uv.inst, syms.botType, null);
-            new_targs = new_targs.append(newArg);
-        }
-        //step 2 - replace synthetic vars in their bounds
-        List<Type> formals = tvars;
-        for (Type t : new_targs.toList()) {
-            CapturedType ct = (CapturedType)t;
-            ct.bound = types.subst(ct.bound, tvars, new_targs.toList());
-            WildcardType wt = new WildcardType(syms.objectType, BoundKind.UNBOUND, syms.boundClass);
-            wt.bound = (TypeVar)formals.head;
-            ct.wildcard = wt;
-            formals = formals.tail;
-        }
-        return new_targs.toList();
-    }
-
-    /** Instantiate a generic method type by finding instantiations for all its
-     * inference variables so that it can be applied to a given argument type list.
-     */
-    public Type instantiateMethod(Env<AttrContext> env,
+    public abstract Type instantiateMethod(Env<AttrContext> env,
                                   List<Type> tvars,
                                   MethodType mt,
                                   Symbol msym,
@@ -382,145 +87,227 @@
                                   boolean allowBoxing,
                                   boolean useVarargs,
                                   Resolve.MethodResolutionContext resolveContext,
-                                  Warner warn) throws InferenceException {
-        //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
-        final InferenceContext inferenceContext = new InferenceContext(tvars);
-        
-        rs.checkRawArgumentsAcceptable(env, resolveContext.attrMode(), inferenceContext, argtypes, mt.getParameterTypes(),
-                allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
-
-        // minimize as yet undetermined type variables
-        inferenceContext.instantiate(warn, false, EnumSet.of(InferenceKind.LOWER));
-        
-        checkWithinBounds(tvars, inferenceContext.asFree(inferenceContext.insttypes), warn);
-
-        mt = (MethodType)inferenceContext.asInstType(mt);
-        
-        List<Type> restvars = inferenceContext.restvars(); 
-        
-        if (!restvars.isEmpty()) {
-            if (resultInfo != null) {
-                instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);            
-                checkWithinBounds(tvars, inferenceContext.asInstTypes(tvars), warn);
-                mt = (MethodType)inferenceContext.asInstType(mt);
-                inferenceContext.finish();
-                if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
-                    log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
-                }
-            }
-        } else {
-            inferenceContext.finish();
-        }
-        
-        // return instantiated version of method type
-        return mt;
-    }
-
-        /** inference check handler **/
-        class InferenceCheckHandler implements Resolve.MethodCheckHandler {
-
-            InferenceContext inferenceContext;
-
-            public InferenceCheckHandler(InferenceContext inferenceContext) {
-                this.inferenceContext = inferenceContext;
-            }
-
-            public InapplicableMethodException arityMismatch() {
-                return unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
-            }
-            public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
-                String key = varargs ?
-                        "infer.varargs.argument.mismatch" :
-                        "infer.no.conforming.assignment.exists";
-                return unambiguousNoInstanceException.setMessage(key,
-                        inferenceContext.inferenceVars(), details);
-            }
-            public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
-                return unambiguousNoInstanceException.setMessage("inaccessible.varargs.type",
-                        expected, Kinds.kindName(location), location);
-            }
-        }
+                                  Warner warn) throws InferenceException;
     
-    // <editor-fold desc="SAM type instantiation">
     /**
      * This method is used to infer a suitable target SAM in case the original
      * SAM type contains one or more wildcards. An inference process is applied
      * so that wildcard bounds, as well as explicit lambda/method ref parameters
      * (where applicable) are used to constraint the solution.
      */
-    public Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) {
-        if (types.capture(samType) == samType) {
-            //if capture doesn't change the type then return the target unchanged
-            //(this means the target contains no wilddcards!)
-            return samType;
-        } else {
-            Type formalSam = samType.tsym.type;
-            InferenceContext samInferenceContext = new InferenceContext(samType.tsym.type.getTypeArguments());
-            if (paramTypes != null) {
-                //get constraints from explicit params (this is done by
-                //checking that explicit param types are equal to the ones
-                //in the SAM descriptors)
-                List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes();
-                if (descParameterTypes.size() != paramTypes.size()) {
-                    checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
-                    return types.createErrorType(samType);
-                }
-                for (Type p : descParameterTypes) {
-                    if (!types.isSameType(samInferenceContext.asFree(p), paramTypes.head)) {
-                        checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
-                        return types.createErrorType(samType);
-                    }
-                    paramTypes = paramTypes.tail;
-                }
-                samInferenceContext.instantiate(Warner.noWarnings, true,
-                        EnumSet.of(InferenceKind.LOWER, InferenceKind.UPPER));
-                
-                formalSam = samInferenceContext.asInstType(formalSam);
-            }
-            ListBuffer<Type> typeargs = ListBuffer.lb();
-            List<Type> actualTypeargs = samType.getTypeArguments();
-            //for remaining uninferred type-vars in the SAM type,
-            //simply replace the wildcards with its bound
-            for (Type t : formalSam.getTypeArguments()) {
-                if (actualTypeargs.head.tag == WILDCARD) {
-                    WildcardType wt = (WildcardType)actualTypeargs.head;
-                    typeargs.append(wt.type);
-                } else {
-                    typeargs.append(actualTypeargs.head);
-                }
-                actualTypeargs = actualTypeargs.tail;
-            }
-            Type owntype = types.subst(formalSam, samInferenceContext.inferenceVars(), typeargs.toList());
-            if (!chk.checkValidGenericType(owntype)) {
-                //if the inferred SAM type is not well-formed, or if it's not
-                //a subtype of the original target, issue an error
-                checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
-                return types.createErrorType(samType);
-            }
-            return owntype;
+    public abstract Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext);
+
+    /** 
+     * Inference check handler - used to report inference error during method
+     * instantiation (see Infer.intantiateMethod).
+     */
+    class InferenceCheckHandler implements Resolve.MethodCheckHandler {
+
+        InferenceContext inferenceContext;
+
+        public InferenceCheckHandler(InferenceContext inferenceContext) {
+            this.inferenceContext = inferenceContext;
+        }
+
+        public InapplicableMethodException arityMismatch() {
+            return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
+        }
+        public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic diag) {
+            String key = varargs ?
+                    "infer.varargs.argument.mismatch" :
+                    "infer.no.conforming.assignment.exists";
+            return inferenceException.setMessage(key,
+                    inferenceContext.inferenceVars(), diag);
+        }
+        public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
+            return inferenceException.setMessage("inaccessible.varargs.type",
+                    expected, Kinds.kindName(location), location);
         }
     }
     // </editor-fold>
 
-    /** check that type parameters are within their bounds.
+    // <editor-fold defaultstate="collapsed" desc="Bound checking">
+    
+    /**
+     * This interface defines an entry point for doing inference variable
+     * bound incorporation - it can be used to inject custom incorporation
+     * logic into the basic bound checking routine
+     */
+    interface IncorporationStep {
+        void apply(UndetVar uv, InferenceContext inferenceContext);
+    }
+    
+    /** 
+     * Check that type parameters are within their bounds.
      */
-    void checkWithinBounds(List<Type> tvars,
-                                   List<Type> arguments,
-                                   Warner warn)
-        throws InvalidInstanceException {
-        for (List<Type> tvs = tvars, args = arguments;
-             tvs.nonEmpty();
-             tvs = tvs.tail, args = args.tail) {
-            if (args.head instanceof UndetVar ||
-                    tvars.head.getUpperBound().isErroneous()) continue;
-            List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments);
-            if (!types.isSubtypeUnchecked(args.head, bounds, warn))
-                throw invalidInstanceException
-                    .setMessage("inferred.do.not.conform.to.bounds",
-                                args.head, bounds);
+    void checkWithinBounds(InferenceContext inferenceContext,
+                             Warner warn, IncorporationStep... incorporationSteps) throws InferenceException {
+        MultiUndetVarListener mlistener = new MultiUndetVarListener(inferenceContext.undetvars);
+        try {
+            while (true) {
+                mlistener.changed = false;
+                for (Type t : inferenceContext.undetvars) {
+                    UndetVar uv = (UndetVar)t;
+                    uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.insttypes(), types);
+                    checkCompatibleUpperBounds(uv, inferenceContext);
+                    if (uv.inst != null) {
+                        Type inst = uv.inst;
+                        for (Type u : uv.getBounds(InferenceBound.UPPER)) {
+                            if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
+                                reportBoundError(uv, BoundErrorKind.UPPER);
+                            }
+                        }
+                        for (Type l : uv.getBounds(InferenceBound.LOWER)) {
+                            if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), inst, warn)) {
+                                reportBoundError(uv, BoundErrorKind.LOWER);
+                            }
+                        }
+                        for (Type e : uv.getBounds(InferenceBound.EQ)) {
+                            if (!types.isSameType(inst, inferenceContext.asFree(e, types))) {
+                                reportBoundError(uv, BoundErrorKind.EQ);
+                            }
+                        }
+                    }
+                    //check eq bounds consistency
+                    for (Type e : uv.getBounds(InferenceBound.EQ)) {
+                        if (e.containsAny(inferenceContext.inferenceVars())) continue;
+                        for (Type u : uv.getBounds(InferenceBound.UPPER)) {
+                            if (!types.isSubtypeUnchecked(e, inferenceContext.asFree(u, types), warn)) {
+                                reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER);
+                            }
+                        }
+                        for (Type l : uv.getBounds(InferenceBound.LOWER)) {
+                            if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), e, warn)) {
+                                reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER);
+                            }
+                        }
+                    }
+                    //bound incorporation
+                    for (IncorporationStep is : incorporationSteps) {
+                        is.apply(uv, inferenceContext);
+                    }
+                }
+                if (!mlistener.changed) break;
+            }
+        }
+        finally {
+            mlistener.detach();
         }
     }
+    //where
+        /**
+         * This listener keeps track of changes on a group of inference variable
+         * bounds. Note: the listener must be detached (calling corresponding
+         * method) to make sure that the underlying inference variable is
+         * left in a clean state.
+         */
+        class MultiUndetVarListener implements UndetVar.UndetVarListener {
 
+            boolean changed;
+            List<Type> undetvars;
+
+            public MultiUndetVarListener(List<Type> undetvars) {
+                this.undetvars = undetvars;
+                for (Type t : undetvars) {
+                    UndetVar uv = (UndetVar)t;
+                    uv.listener = this;
+                }
+            }
+
+            public void varChanged(UndetVar uv, Set<InferenceBound> ibs) {
+                changed = true;
+            }
+
+            void detach() {
+                for (Type t : undetvars) {
+                    UndetVar uv = (UndetVar)t;
+                    uv.listener = null;
+                }
+            }                
+        };
+
+    void checkCompatibleUpperBounds(UndetVar uv, InferenceContext inferenceContext) {
+        // VGJ: sort of inlined maximizeInst() below.  Adding
+        // bounds can cause lobounds that are above hibounds.
+        List<Type> hibounds = Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext));
+        Type hb = null;
+        if (hibounds.isEmpty())
+            hb = syms.objectType;
+        else if (hibounds.tail.isEmpty())
+            hb = hibounds.head;
+        else
+           hb = types.glb(hibounds);
+        if (hb == null || hb.isErroneous())
+            reportBoundError(uv, BoundErrorKind.BAD_UPPER);
+    }
+    //where
+            protected class BoundFilter implements Filter<Type> {
+                
+                InferenceContext inferenceContext;
+
+                public BoundFilter(InferenceContext inferenceContext) {
+                    this.inferenceContext = inferenceContext;
+                }
+
+                @Override
+                public boolean accepts(Type t) {
+                    return !t.isErroneous() && !inferenceContext.free(t);
+                }
+            };
+
+    enum BoundErrorKind {
+        BAD_UPPER() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("incompatible.upper.bounds", uv.qtype,
+                        uv.getBounds(InferenceBound.UPPER));
+            }
+        },
+        BAD_EQ_UPPER() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype,
+                        uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER));
+            }
+        },
+        BAD_EQ_LOWER() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype,
+                        uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER));
+            }
+        },
+        UPPER() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst,
+                        uv.getBounds(InferenceBound.UPPER));
+            }
+        },
+        LOWER() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst,
+                        uv.getBounds(InferenceBound.LOWER));
+            }
+        },
+        EQ() {
+            @Override
+            InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
+                return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst,
+                        uv.getBounds(InferenceBound.EQ));
+            }
+        };
+
+        abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
+    }
+    //where
+    void reportBoundError(UndetVar uv, BoundErrorKind bk) {
+        throw bk.setMessage(inferenceException, uv);
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Polymorphic signature inference (JSR 292)">
     /**
      * Compute a synthetic method type corresponding to the requested polymorphic
      * method signature. The target return type is computed from the immediately
@@ -584,34 +371,8 @@
                 }
         };
     // </editor-fold>
-        
-   /**
-    * Single-method-interface for defining inference callbacks. Certain actions
-    * (i.e. subtyping checks) might need to be redone after all inference variables
-    * have been fixed.
-    */   
-    interface PendingCheck {
-        void eval();
-    }
-    
-    /**
-     * There are two kind of inference strategies: (i) lower bounds can be used to
-     * infer a type using lub, alternatively (ii) upper bounds can be used to
-     * infer a type using glb.
-     */
-    enum InferenceKind {
-        LOWER,
-        UPPER;
-        
-        boolean upperBoundInference() {
-            return this == UPPER;
-        }
-        
-        boolean lowerBoundInference() {
-            return this == LOWER;
-        }
-    }
-    
+
+    // <editor-fold defaultstate="collapsed" desc="Inference context">
     /**
      * An inference context keeps track of the set of variables that are free
      * in the current context. It provides utility methods for opening/closing
@@ -620,18 +381,33 @@
      * it can be used as an entry point for performing upper/lower bound inference
      * (see InferenceKind).
      */
-    class InferenceContext {
+    static abstract class InferenceContext {
+        
+        /**
+        * Single-method-interface for defining inference callbacks. Certain actions
+        * (i.e. subtyping checks) might need to be redone after all inference variables
+        * have been fixed.
+        */   
+        interface PendingCheck {
+            void eval();
+        }
         
         /** list of inference vars as undet vars */
         List<Type> undetvars;
-        /** list of instantiated types in this context */
-        List<Type> insttypes;
         
         ListBuffer<PendingCheck> pendingChecks = ListBuffer.lb();
         
-        public InferenceContext(List<Type> inferenceVars) {
-            this.undetvars = Type.map(inferenceVars, fromTypeVarFun);
-            this.insttypes = inferenceVars;
+        public InferenceContext(List<Type> inferenceVars, final Types types) {
+            this(inferenceVars, types, true);
+        }
+        
+        public InferenceContext(List<Type> inferenceVars, final Types types, final boolean includeBounds) {
+            this.undetvars = Type.map(inferenceVars, new Mapping("fromTypeVarFun") {
+                public Type apply(Type t) {
+                    if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, includeBounds, types);
+                    else return t.map(this);
+                }
+            });
         }
 
         /**
@@ -645,6 +421,19 @@
             }
             return tvars.toList();
         }
+        
+        List<Type> insttypes() {
+            ListBuffer<Type> insttypes = ListBuffer.lb();
+            for (Type t : undetvars) {
+                UndetVar uv = (UndetVar)t;
+                if (uv.inst != null) {
+                    insttypes.append(uv.inst);
+                } else {
+                    insttypes.append(uv.qtype);
+                }
+            }
+            return insttypes.toList();
+        }
 
         /**
          * returns the list of uninstantiated variables (as type-variables) in this
@@ -653,7 +442,7 @@
         List<Type> restvars() {
             List<Type> undetvars = this.undetvars;
             ListBuffer<Type> restvars = ListBuffer.lb();
-            for (Type t : insttypes) {
+            for (Type t : insttypes()) {
                 UndetVar uv = (UndetVar)undetvars.head;
                 if (uv.qtype == t) {
                     restvars.append(t);
@@ -676,20 +465,44 @@
             }
             return false;
         }
+        
+        final List<Type> freeVarsIn(Type t) {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            for (Type iv : inferenceVars()) {
+                if (t.contains(iv)) {
+                    buf.add(iv);
+                }
+            }
+            return buf.toList();
+        }
+        
+        final List<Type> freeVarsIn(List<Type> ts) {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            for (Type t : ts) {
+                buf.appendList(freeVarsIn(t));
+            }
+            ListBuffer<Type> buf2 = ListBuffer.lb();
+            for (Type t : buf) {
+                if (!buf2.contains(t)) {
+                    buf2.add(t);
+                }
+            }
+            return buf2.toList();
+        }
 
         /**
          * Replace all free variables in a given type with corresponding
          * undet vars (used ahead of subtyping/compatibility checks to allow propagation
          * of inference constraints).
          */
-        final Type asFree(Type t) {
+        final Type asFree(Type t, Types types) {
             return types.subst(t, inferenceVars(), undetvars);
         }
         
-        final List<Type> asFree(List<Type> ts) {
+        final List<Type> asFree(List<Type> ts, Types types) {
             ListBuffer<Type> buf = ListBuffer.lb();
             for (Type t : ts) {
-                buf.append(asFree(t));
+                buf.append(asFree(t, types));
             }
             return buf.toList();
         }
@@ -699,48 +512,20 @@
          * instantiated types - if one or more free variable has not been
          * fully instantiated, it will still be available in the resulting type.
          */
-        Type asInstType(Type t) {
-            return types.subst(t, inferenceVars(), insttypes);
-        }
-        
-        List<Type> asInstTypes(List<Type> ts) {
-            ListBuffer<Type> buf = ListBuffer.lb();
-            for (Type t : ts) {
-                buf.append(asInstType(t));
-            }
-            return buf.toList();
+        Type asInstType(Type t, Types types) {
+            return types.subst(t, inferenceVars(), insttypes());
         }
         
-        /**
-         * Perform upper/lower type-inference
-         */
-        void instantiate(Warner warn, boolean skipIfNoBounds, EnumSet<InferenceKind> iks) {
-            for (InferenceKind ik : InferenceKind.values()) {
-                if (!iks.contains(ik)) continue;
-                for (Type t : undetvars) {
-                    UndetVar uv = (UndetVar)t;
-                    if (ik.lowerBoundInference() &&
-                            (uv.lobounds.nonEmpty() || !skipIfNoBounds)) {
-                        minimizeInst((UndetVar) t, warn);
-                    } else if (ik.upperBoundInference() &&
-                            (uv.hibounds.nonEmpty() || !skipIfNoBounds)) {
-                        maximizeInst((UndetVar) t, warn);
-                    }
-                }                
-
-                insttypes = List.nil();
-
-                for (Type t : undetvars) {
-                    UndetVar uv = (UndetVar)t;
-                    if (uv.inst == null || uv.inst.tag == BOT) {
-                        uv.inst = null;
-                        insttypes = insttypes.append(uv.qtype);
-                    } else {
-                        insttypes = insttypes.append(uv.inst);
-                    }
-                }
+        List<Type> asInstTypes(List<Type> ts, Types types) {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            boolean changed = false;
+            for (Type t : ts) {
+               Type t2 = asInstType(t, types);
+               changed |= t2 != t;
+               buf.append(t2);
             }
-        }
+            return changed ? buf.toList() : ts;
+         }
         
         /**
          * Add custom hook for performing post-inference action
@@ -754,12 +539,20 @@
          * of all deferred checks.
          */
         void finish() {
-            Assert.check(!free(insttypes));
+            Assert.check(restvars().isEmpty());
             for (PendingCheck pc : pendingChecks) {
                 pc.eval();
             }
         }
+        
+        abstract void solveAny(List<Type> stuckvars);
     }
     
-    final InferenceContext emptyContext = new InferenceContext(List.<Type>nil());
+    final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), types) {
+        @Override
+        void solveAny(List<Type> stuckvars) {
+            Assert.error();
+        }
+    };
+    // </editor-fold>
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/InferFactory.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Options;
+
+/**
+ * A factory for creating inference engines.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class InferFactory {
+
+    /** The context key for the infer factory. */
+    protected static final Context.Key<InferFactory> inferFactoryKey = new Context.Key<InferFactory>();
+
+    public static InferFactory instance(Context context) {
+        InferFactory instance = context.get(inferFactoryKey);
+        if (instance == null) {
+            instance = new InferFactory(context);
+        }
+        return instance;
+    }
+
+    final Infer infer;
+
+    protected InferFactory(Context context) {
+        context.put(inferFactoryKey, this);
+        Source source = Source.instance(context);
+        Options options = Options.instance(context);
+        infer = source.allowBetterInference() && options.isSet("useGraphInference") ?
+                new GraphInfer(context) : new LegacyInfer(context);
+    }
+    
+    public Infer getInfer() {
+        return infer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+import static com.sun.tools.javac.code.TypeTags.*;
+
+/** Helper class for type parameter inference, used by the attribution phase.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class LegacyInfer extends Infer {
+
+    Check chk;
+    Resolve rs;
+    Log log;
+
+    protected LegacyInfer(Context context) {
+        super(context);
+        rs = Resolve.instance(context);
+        log = Log.instance(context);
+        chk = Check.instance(context);
+    }
+
+/***************************************************************************
+ * Mini/Maximization of UndetVars
+ ***************************************************************************/
+
+    /** Instantiate undetermined type variable to its minimal upper bound.
+     *  Throw a NoInstanceException if this not possible.
+     */
+    private void maximizeInst(UndetVar that, InferenceContext inferenceContext) throws InferenceException {
+        List<Type> hibounds = Type.filter(that.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext));
+        if (that.getBounds(InferenceBound.EQ).isEmpty()) {
+            if (hibounds.isEmpty())
+                that.inst = syms.objectType;
+            else if (hibounds.tail.isEmpty())
+                that.inst = hibounds.head;
+            else
+                that.inst = types.glb(hibounds);
+        } else {
+            that.inst = that.getBounds(InferenceBound.EQ).head;
+        }
+        if (that.inst == null ||
+            that.inst.isErroneous())
+            throw inferenceException
+                .setMessage("no.unique.maximal.instance.exists",
+                            that.qtype, hibounds);
+    }
+
+    /** Instantiate undetermined type variable to the lub of all its lower bounds.
+     *  Throw a NoInstanceException if this not possible.
+     */
+    private void minimizeInst(UndetVar that, InferenceContext inferenceContext) throws InferenceException {
+        List<Type> lobounds = Type.filter(that.getBounds(InferenceBound.LOWER), new BoundFilter(inferenceContext));
+        if (that.getBounds(InferenceBound.EQ).isEmpty()) {
+            if (lobounds.nonEmpty()) {
+                if (lobounds.tail.isEmpty())
+                    that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
+                else {
+                    that.inst = types.lub(lobounds);
+                }
+                if (that.inst == null || that.inst.tag == ERROR)
+                        throw inferenceException
+                            .setMessage("no.unique.minimal.instance.exists",
+                                        that.qtype, lobounds);
+            }
+        } else {
+            that.inst = that.getBounds(InferenceBound.EQ).head;
+        }
+    }
+
+/***************************************************************************
+ * Exported Methods
+ ***************************************************************************/
+
+    /** 
+     * Instantiate uninferred inference variables (JLS 15.12.2.8). First
+     * if the method return type is non-void, we derive constraints from the
+     * expected type - then we use declared bound well-formedness to derive additional
+     * constraints. If no instantiation exists, or if several incomparable
+     * best instantiations exist throw a NoInstanceException.
+     */
+    private void instantiateUninferred(DiagnosticPosition pos,
+            InferenceContext inferenceContext,
+            MethodType mtype,
+            Attr.ResultInfo resultInfo) throws InferenceException {
+        Type to = resultInfo.pt;
+        if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
+            to = mtype.getReturnType().tag <= VOID ?
+            mtype.getReturnType() : syms.objectType;
+        }
+        Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
+        if (!types.isSubtype(qtype1,
+                qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
+            throw inferenceException
+                    .setMessage("infer.no.conforming.instance.exists",
+                    inferenceContext.restvars(), mtype.getReturnType(), to);
+        }
+        
+        while (true) {
+            boolean stuck = true;
+            for (Type t : inferenceContext.undetvars) {
+                UndetVar uv = (UndetVar)t;
+                if (uv.inst == null &&
+                        (uv.getBounds(InferenceBound.EQ).nonEmpty() ||
+                        !inferenceContext.free(uv.getBounds(InferenceBound.UPPER)))) {
+                    maximizeInst((UndetVar)t, inferenceContext);
+                    stuck = false;
+                }
+            }
+            if (inferenceContext.restvars().isEmpty()) {
+                //all variables have been instantiated - exit
+                break;
+            } else if (stuck) {
+                //some variables could not be instantiated because of cycles in
+                //upper bounds - provide a (possibly recursive) default instantiation
+                instantiateAsUninferredVars(inferenceContext);
+                break;
+            } else {
+                //some variables have been instantiated - replace newly instantiated
+                //variables in remaining upper bounds and continue
+                for (Type t : inferenceContext.undetvars) {
+                    UndetVar uv = (UndetVar)t;
+                    uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.insttypes(), types);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Infer cyclic inference variables as described in 15.12.2.8.
+     */
+    private void instantiateAsUninferredVars(InferenceContext inferenceContext) {
+        ListBuffer<Type> todo = ListBuffer.lb();
+        //step 1 - create fresh tvars
+        for (Type t : inferenceContext.undetvars) {
+            UndetVar uv = (UndetVar)t;
+            if (uv.inst == null) {
+                TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
+                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
+                todo.append(uv);
+                uv.inst = fresh_tvar.type;
+            }
+        }
+        //step 2 - replace fresh tvars in their bounds
+        List<Type> formals = inferenceContext.inferenceVars();
+        for (Type t : todo) {
+            UndetVar uv = (UndetVar)t;
+            TypeVar ct = (TypeVar)uv.inst;
+            ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
+            if (ct.bound.isErroneous()) {
+                //report inference error if glb fails
+                reportBoundError(uv, BoundErrorKind.BAD_UPPER);
+            }
+            formals = formals.tail;
+        }
+    }
+    
+    @Override
+    public Type instantiateMethod(Env<AttrContext> env,
+                                  List<Type> tvars,
+                                  MethodType mt,
+                                  Symbol msym,
+                                  Attr.ResultInfo resultInfo,
+                                  List<Type> argtypes,
+                                  boolean allowBoxing,
+                                  boolean useVarargs,
+                                  Resolve.MethodResolutionContext resolveContext,
+                                  Warner warn) throws InferenceException {
+        //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
+        final InferenceContext inferenceContext = new LegacyInferenceContext(tvars, true);
+        
+        rs.checkRawArgumentsAcceptable(env, resultInfo != null ? DeferredAttr.AttrMode.CHECK : DeferredAttr.AttrMode.SPECULATIVE, inferenceContext, argtypes, mt.getParameterTypes(),
+                allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
+
+        // minimize as yet undetermined type variables
+        for (Type t : inferenceContext.undetvars) {
+            minimizeInst((UndetVar)t, inferenceContext);
+        }
+        
+        checkWithinBounds(inferenceContext, warn);
+
+        mt = (MethodType)inferenceContext.asInstType(mt, types);
+        
+        List<Type> restvars = inferenceContext.restvars(); 
+        
+        if (!restvars.isEmpty() && resultInfo != null &&
+                !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
+            if (resultInfo != null) {
+                instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo);
+                checkWithinBounds(inferenceContext, warn);
+                mt = (MethodType)inferenceContext.asInstType(mt, types);
+                inferenceContext.finish();
+                if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
+                    log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
+                }
+            }
+        } else if (restvars.isEmpty()) {
+            inferenceContext.finish();
+        }
+        
+        // return instantiated version of method type
+        return mt;
+    }
+    
+    @Override
+    public Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) {
+        if (types.capture(samType) == samType) {
+            //if capture doesn't change the type then return the target unchanged
+            //(this means the target contains no wilddcards!)
+            return samType;
+        } else {
+            Type formalSam = samType.tsym.type;
+            InferenceContext samInferenceContext = new LegacyInferenceContext(samType.tsym.type.getTypeArguments(), false);
+            if (paramTypes != null) {
+                //get constraints from explicit params (this is done by
+                //checking that explicit param types are equal to the ones
+                //in the SAM descriptors)
+                List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes();
+                if (descParameterTypes.size() != paramTypes.size()) {
+                    checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                    return types.createErrorType(samType);
+                }
+                for (Type p : descParameterTypes) {
+                    if (!types.isSameType(samInferenceContext.asFree(p, types), paramTypes.head)) {
+                        checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                        return types.createErrorType(samType);
+                    }
+                    paramTypes = paramTypes.tail;
+                }
+                for (Type t : samInferenceContext.undetvars) {
+                    UndetVar uv = (UndetVar)t;
+                    minimizeInst(uv, checkContext.inferenceContext());
+                    if (uv.inst == null &&
+                            Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(checkContext.inferenceContext())).nonEmpty()) {
+                        maximizeInst(uv, samInferenceContext);
+                    }
+                }
+                
+                formalSam = samInferenceContext.asInstType(formalSam, types);
+            }
+            ListBuffer<Type> typeargs = ListBuffer.lb();
+            List<Type> actualTypeargs = samType.getTypeArguments();
+            //for remaining uninferred type-vars in the SAM type,
+            //simply replace the wildcards with its bound
+            for (Type t : formalSam.getTypeArguments()) {
+                if (actualTypeargs.head.tag == WILDCARD) {
+                    WildcardType wt = (WildcardType)actualTypeargs.head;
+                    typeargs.append(wt.type);
+                } else {
+                    typeargs.append(actualTypeargs.head);
+                }
+                actualTypeargs = actualTypeargs.tail;
+            }
+            Type owntype = types.subst(formalSam, samInferenceContext.inferenceVars(), typeargs.toList());
+            if (!chk.checkValidGenericType(owntype)) {
+                //if the inferred SAM type is not well-formed, or if it's not
+                //a subtype of the original target, issue an error
+                checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
+                return types.createErrorType(samType);
+            }
+            return owntype;
+        }
+    }
+    
+    /**
+     * Simple inference context - on-demand inference variable solving is addressed
+     * by instantiating at least one variable using lower bound inference
+     */
+    class LegacyInferenceContext extends InferenceContext {
+
+        public LegacyInferenceContext(List<Type> inferenceVars, boolean includeBounds) {
+            super(inferenceVars, types, includeBounds);
+        }
+        
+        @Override
+        void solveAny(List<Type> varsToSolve) {
+            boolean progress = false;
+            for (Type t : varsToSolve) {
+                UndetVar uv = (UndetVar)asFree(t, types);
+                minimizeInst(uv, this);
+                if (uv.inst != null) {
+                    progress = true;
+                }
+            }
+            if (!progress) {
+                throw inferenceException.setMessage();
+            }
+        }
+    }
+}
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Aug 03 12:48:20 2012 +0100
@@ -33,6 +33,7 @@
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
+import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
@@ -46,6 +47,7 @@
 import java.util.Collection;
 import java.util.EnumMap;
 import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -112,7 +114,7 @@
         attr = Attr.instance(context);
         deferredAttr = DeferredAttr.instance(context);
         chk = Check.instance(context);
-        infer = Infer.instance(context);
+        infer = InferFactory.instance(context).getInfer();
         reader = ClassReader.instance(context);
         treeinfo = TreeInfo.instance(context);
         types = Types.instance(context);
@@ -686,30 +688,33 @@
             varargsAccessible(env, elt, handler, inferenceContext);
         }
         
-        boolean unstuckRound = false;
         while (!deferredTypeQueue.isEmpty()) {
+            List<Type> stuckVars = List.nil();
             Map<DeferredType<?>, ResultInfo> todo =
                     new LinkedHashMap<DeferredType<?>, ResultInfo>();
             for (Map.Entry<DeferredType<?>, ResultInfo> e : deferredTypeQueue.entrySet()) {
                 DeferredType<?> ptype = e.getKey();
                 ResultInfo mresult = e.getValue();
-                mresult = mresult.dup(inferenceContext.asInstType(mresult.pt));
+                mresult = mresult.dup(inferenceContext.asInstType(mresult.pt, types));
                 try {
                     deferredAttr.attribDeferred(ptype, mode, mresult);
                 } catch (DeferredAttr.StuckDeferredAttrException ex) {
+                    for (Type t : ex.tvars) {
+                        if (!stuckVars.contains(t)) {
+                            stuckVars = stuckVars.prepend(t);
+                        }
+                    }
                     todo.put(ptype, mresult);
                 }
             }
             if (todo.size() == deferredTypeQueue.size()) {
-                if (unstuckRound) {
+                //instantiate a portion of the stuck vars and resume checking
+                try {
+                    inferenceContext.solveAny(stuckVars);
+                } catch (Infer.InferenceException ex) {
+                    //this can only happen with the legacy solver
                     throw new Infer.InferenceException(diags).setMessage("cyclic.lambda.inference");
-                } else {
-                    //lower bound inst
-                    inferenceContext.instantiate(warn, true, EnumSet.of(Infer.InferenceKind.LOWER));
-                    unstuckRound = true;
-            }
-            } else {
-                unstuckRound = false;
+                }
             }
             deferredTypeQueue = todo;
         }
@@ -717,9 +722,9 @@
     
     void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
         if (inferenceContext.free(t)) {
-            inferenceContext.addPendingCheck(new Infer.PendingCheck() {
+            inferenceContext.addPendingCheck(new PendingCheck() {
                 public void eval() {
-                    varargsAccessible(env, inferenceContext.asInstType(t), handler, inferenceContext);
+                    varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext);
                 }
             });
         } else {
@@ -772,7 +777,7 @@
         }
 
         public boolean compatible(Type found, Type req, Warner warn) {
-            return types.isSubtypeUnchecked(found, inferenceContext.asFree(req), warn);
+            return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn);
         }
 
         public boolean allowBoxing() {
@@ -791,7 +796,7 @@
         }
 
         public boolean compatible(Type found, Type req, Warner warn) {
-            return types.isConvertible(found, inferenceContext.asFree(req), warn);
+            return types.isConvertible(found, inferenceContext.asFree(req, types), warn);
         }
 
         public boolean allowBoxing() {
@@ -2143,7 +2148,7 @@
      *  @param typeargtypes  The types of the constructor invocation's type
      *                   arguments.
      */
-    Symbol resolveDiamond(DiagnosticPosition pos,
+    Pair<Symbol, Symbol> resolveDiamond(DiagnosticPosition pos,
                               Env<AttrContext> env,
                               Type site,
                               List<Type> argtypes,
@@ -2151,23 +2156,23 @@
         MethodResolutionContext prevResolutionContext = currentResolutionContext;
         try {
             currentResolutionContext = new MethodResolutionContext();
-            Symbol sym = methodNotFound;
+            Pair<Symbol, Symbol> res = new Pair<Symbol, Symbol>(methodNotFound, methodNotFound);
             List<MethodResolutionPhase> steps = methodResolutionSteps;
             while (steps.nonEmpty() &&
                    steps.head.isApplicable(boxingEnabled, varargsEnabled) &&
-                   sym.kind >= ERRONEOUS) {
+                   res.fst.kind >= ERRONEOUS) {
                 currentResolutionContext.step = steps.head;
-                sym = findDiamond(env, site, argtypes, typeargtypes,
+                res = findDiamond(env, site, argtypes, typeargtypes,
                         steps.head.isBoxingRequired(),
                         env.info.varArgs = steps.head.isVarargsRequired());
-                currentResolutionContext.resolutionCache.put(steps.head, sym);
+                currentResolutionContext.resolutionCache.put(steps.head, res.fst);
                 steps = steps.tail;
             }
-            if (sym.kind >= AMBIGUOUS) {
+            if (res.fst.kind >= AMBIGUOUS) {
                 Symbol errSym =
                         currentResolutionContext.resolutionCache.get(currentResolutionContext.firstErroneousResolutionPhase());
                 final JCDiagnostic details = errSym.kind == WRONG_MTH ?
-                        ((InapplicableSymbolError)errSym).errCandidate().details :
+                                currentResolutionContext.candidates.head.details :
                                 null;
                 errSym = new ResolveError(WRONG_MTH, "diamond error") {
                     @Override
@@ -2181,10 +2186,10 @@
                     }
                 };
                 MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase();
-                sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes);
+                res = new Pair<Symbol, Symbol>(access(errSym, pos, site, names.init, true, argtypes, typeargtypes), res.snd);
                 env.info.varArgs = errPhase.isVarargsRequired();
             }
-            return sym;
+            return res;
         }
         finally {
             currentResolutionContext = prevResolutionContext;
@@ -2199,13 +2204,14 @@
      *  inference. The inferred return type of the synthetic constructor IS
      *  the inferred type for the diamond operator.
      */
-    private Symbol findDiamond(Env<AttrContext> env,
+    private Pair<Symbol, Symbol> findDiamond(Env<AttrContext> env,
                               Type site,
                               List<Type> argtypes,
                               List<Type> typeargtypes,
                               boolean allowBoxing,
                               boolean useVarargs) {
         Symbol bestSoFar = methodNotFound;
+        Map<Symbol, Symbol> constrMap = new HashMap<Symbol, Symbol>();
         for (Scope.Entry e = site.tsym.members().lookup(names.init);
              e.scope != null;
              e = e.next()) {
@@ -2217,15 +2223,17 @@
                             List.<Type>nil();
                     Type constrType = new ForAll(site.tsym.type.getTypeArguments().appendList(oldParams),
                             types.createMethodTypeWithReturn(e.sym.type.asMethodType(), site));
+                    MethodSymbol newConstr = new MethodSymbol(e.sym.flags(), names.init, constrType, site.tsym);
+                    constrMap.put(newConstr, e.sym);
                     bestSoFar = selectBest(env, site, argtypes, typeargtypes,
-                            new MethodSymbol(e.sym.flags(), names.init, constrType, site.tsym),
+                            newConstr,
                             bestSoFar,
                             allowBoxing,
                             useVarargs,
                             false);
             }
         }
-        return bestSoFar;
+        return new Pair<Symbol, Symbol>(bestSoFar, constrMap.containsKey(bestSoFar) ? constrMap.get(bestSoFar) : syms.errSymbol);
     }
     
     /**
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Aug 03 12:48:20 2012 +0100
@@ -1638,14 +1638,6 @@
 ## The following are all possible strings for the last argument of all those
 ## diagnostics whose key ends in ".1"
 
-# 0: type, 1: message segment
-compiler.misc.undetermined.type=\
-    cannot infer type arguments for {0}\n\
-    reason: {1}
-
-compiler.misc.type.variable.has.undetermined.type=\
-    type variable {0} has undetermined type
-
 # 0: type, 1: list of type
 compiler.misc.no.unique.maximal.instance.exists=\
     no unique maximal instance exists for type variable {0} with upper bounds {1}
@@ -1657,6 +1649,18 @@
 compiler.misc.incompatible.upper.bounds=\
     inference variable {0} has incompatible upper bounds {1}
 
+# 0: type, 1: list of type, 2: list of type
+compiler.misc.incompatible.eq.upper.bounds=\
+    inference variable {0} has incompatible bounds\n\
+    equality constraints: {1}\n\
+    upper bounds: {2}
+
+# 0: type, 1: list of type, 2: list of type
+compiler.misc.incompatible.eq.lower.bounds=\
+    inference variable {0} has incompatible bounds\n\
+    equality constraints: {1}\n\
+    lower bounds: {2}
+
 # 0: list of type, 1: type, 2: type
 compiler.misc.infer.no.conforming.instance.exists=\
     no instance(s) of type variable(s) {0} exist so that {1} conforms to {2}
@@ -1677,10 +1681,22 @@
     (varargs mismatch; {1})
 
 # 0: type, 1: list of type
-compiler.misc.inferred.do.not.conform.to.bounds=\
-    inferred type does not conform to declared bound(s)\n\
+compiler.misc.inferred.do.not.conform.to.upper.bounds=\
+    inferred type does not conform to upper bound(s)\n\
     inferred: {0}\n\
-    bound(s): {1}
+    upper bound(s): {1}
+
+# 0: type, 1: list of type
+compiler.misc.inferred.do.not.conform.to.lower.bounds=\
+    inferred type does not conform to lower bound(s)\n\
+    inferred: {0}\n\
+    lower bound(s): {1}
+
+# 0: type, 1: list of type
+compiler.misc.inferred.do.not.conform.to.eq.bounds=\
+    inferred type does not conform to equality constraint(s)\n\
+    inferred: {0}\n\
+    equality constraints(s): {1}
 
 # 0: symbol
 compiler.misc.diamond=\
--- a/src/share/classes/com/sun/tools/javac/util/List.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/List.java	Fri Aug 03 12:48:20 2012 +0100
@@ -131,6 +131,14 @@
                 xs = new List<A>(array[i], xs);
         return xs;
     }
+    
+    public static <A> List<A> from(Collection<A> coll) {
+        List<A> xs = nil();
+        for (A a : coll) {
+            xs = new List<A>(a, xs);
+        }
+        return xs;
+    }
 
     /** Construct a list consisting of a given number of identical elements.
      *  @param len    The number of elements in the list.
--- a/test/tools/javac/6758789/T6758789b.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/6758789/T6758789b.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,4 +1,4 @@
-T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<java.lang.Object>
+T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<X>
 T6758789b.java:16:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo<X>, T6758789a.Foo, kindname.class, T6758789a
 - compiler.err.warnings.and.werror
 1 error
--- a/test/tools/javac/Diagnostics/6722234/T6722234b_1.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/Diagnostics/6722234/T6722234b_1.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.type.captureof: 1, ? extends T6722234b>,List<compiler.misc.type.captureof: 2, ? extends T6722234b>, kindname.class, T6722234b, (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: List<compiler.misc.type.captureof: 2, ? extends T6722234b>, List<T>))
+T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.type.captureof: 1, ? extends T6722234b>,List<compiler.misc.type.captureof: 2, ? extends T6722234b>, kindname.class, T6722234b, (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 2, ? extends T6722234b, compiler.misc.type.captureof: 2, ? extends T6722234b,compiler.misc.type.captureof: 1, ? extends T6722234b)
 1 error
--- a/test/tools/javac/Diagnostics/6722234/T6722234b_2.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/Diagnostics/6722234/T6722234b_2.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,4 +1,4 @@
-T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.captured.type: 1>,List<compiler.misc.captured.type: 2>, kindname.class, T6722234b, (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: List<compiler.misc.captured.type: 2>, List<T>))
+T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.captured.type: 1>,List<compiler.misc.captured.type: 2>, kindname.class, T6722234b, (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.captured.type: 2, compiler.misc.captured.type: 2,compiler.misc.captured.type: 1)
 - compiler.misc.where.description.typevar: T,{(compiler.misc.where.typevar: T, Object, kindname.method, <T>m(List<T>,List<T>))}
 - compiler.misc.where.description.captured.1: compiler.misc.captured.type: 1,compiler.misc.captured.type: 2,{(compiler.misc.where.captured.1: compiler.misc.captured.type: 1, T6722234b, compiler.misc.type.null, ? extends T6722234b),(compiler.misc.where.captured.1: compiler.misc.captured.type: 2, T6722234b, compiler.misc.type.null, ? extends T6722234b)}
 1 error
--- a/test/tools/javac/Diagnostics/6799605/T6799605.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/Diagnostics/6799605/T6799605.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,4 +1,4 @@
-T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.inferred.do.not.conform.to.bounds: compiler.misc.type.captureof: 1, ?, T6799605<compiler.misc.type.captureof: 1, ?>))}
-T6799605.java:18:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: T6799605<compiler.misc.type.captureof: 2, ?>, T6799605<T>))),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))}
-T6799605.java:19:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,T6799605<compiler.misc.type.captureof: 3, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: T6799605<compiler.misc.type.captureof: 2, ?>, T6799605<T>))),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))}
+T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.inferred.do.not.conform.to.upper.bounds: compiler.misc.type.captureof: 1, ?, T6799605<compiler.misc.type.captureof: 1, ?>))}
+T6799605.java:18:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 2, ?, compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))}
+T6799605.java:19:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,T6799605<compiler.misc.type.captureof: 3, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 3, ?, compiler.misc.type.captureof: 3, ?,compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))}
 3 errors
--- a/test/tools/javac/api/TestJavacTaskScanner.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/api/TestJavacTaskScanner.java	Fri Aug 03 12:48:20 2012 +0100
@@ -41,6 +41,8 @@
 import java.util.Arrays;
 import java.util.Stack;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeMirror;
@@ -110,9 +112,13 @@
     void testParseType(TypeElement clazz) {
         DeclaredType type = (DeclaredType)task.parseType("List<String>", clazz);
         for (Element member : elements.getAllMembers((TypeElement)type.asElement())) {
-            TypeMirror mt = types.asMemberOf(type, member);
-            System.out.format("%s : %s -> %s%n", member.getSimpleName(), member.asType(), mt);
-            numParseTypeElements++;
+            //exclude default methods from the count
+            if (member.getEnclosingElement().getKind() == ElementKind.CLASS ||
+                    member.getModifiers().contains(Modifier.ABSTRACT)) {
+                TypeMirror mt = types.asMemberOf(type, member);
+                System.out.format("%s : %s -> %s%n", member.getSimpleName(), member.asType(), mt);
+                numParseTypeElements++;
+            }
         }
     }
 
--- a/test/tools/javac/cast/7123100/T7123100a.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/cast/7123100/T7123100a.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,4 +1,4 @@
-T7123100a.java:14:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), compiler.misc.type.captureof: 1, ?, Z
+T7123100a.java:14:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), E, Z
 - compiler.err.warnings.and.werror
 1 error
 1 warning
--- a/test/tools/javac/defender/Pos01.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/defender/Pos01.java	Fri Aug 03 12:48:20 2012 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
     }
 
     interface ExtendedList<T> extends List<T> {
-        List<T> map(Mapper<T> r) default {
+        List<T> testMap(Mapper<T> r) default {
             return Pos01.<T>listMapper(this, r);
         }
     }
@@ -47,7 +47,7 @@
     public static void main(String[] args) {
        MyList<Integer> l = new MyList<Integer>();
        l.add(1); l.add(2); l.add(3);
-       l.map((Integer x) -> x * x );
+       l.testMap((Integer x) -> x * x );
     }
 
     static <T> List<T> listMapper(List<T> l, Mapper<T> mapper) {
--- a/test/tools/javac/diags/examples.not-yet.txt	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/diags/examples.not-yet.txt	Fri Aug 03 12:48:20 2012 +0100
@@ -62,6 +62,7 @@
 compiler.misc.kindname.type.variable
 compiler.misc.kindname.type.variable.bound
 compiler.misc.kindname.value
+compiler.misc.incompatible.eq.lower.bounds              # cannot happen?
 compiler.misc.no.unique.minimal.instance.exists
 compiler.misc.resume.abort                              # prompt for a response
 compiler.misc.source.unavailable                        # DiagnosticSource
@@ -77,10 +78,8 @@
 compiler.misc.type.captureof.1
 compiler.misc.type.none
 compiler.misc.type.req.exact
-compiler.misc.type.variable.has.undetermined.type
 compiler.misc.unable.to.access.file                     # ClassFile
 compiler.misc.undecl.type.var                           # ClassReader
-compiler.misc.undetermined.type
 compiler.misc.unicode.str.not.supported                 # ClassReader
 compiler.misc.verbose.retro                             # UNUSED
 compiler.misc.verbose.retro.with                        # UNUSED
--- a/test/tools/javac/diags/examples/CantApplyDiamond1.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/diags/examples/CantApplyDiamond1.java	Fri Aug 03 12:48:20 2012 +0100
@@ -23,7 +23,7 @@
 
 // key: compiler.err.prob.found.req
 // key: compiler.misc.cant.apply.diamond.1
-// key: compiler.misc.infer.no.conforming.instance.exists
+// key: compiler.misc.inferred.do.not.conform.to.upper.bounds
 // key: compiler.misc.diamond
 
 class CantApplyDiamond1<X> {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/diags/examples/IncompatibleEqUpperBounds.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//key: compiler.err.cant.apply.symbol.1
+//key: compiler.misc.incompatible.eq.upper.bounds
+
+import java.util.List;
+
+class IncompatibleEqUpperBounds {
+    <S, T extends List<S>> void m(List<? super S> s1, T s2) { }
+
+    void test(List<Integer> li, List<String> ls) {
+        m(li, ls);
+    }
+}
--- a/test/tools/javac/diags/examples/IncompatibleTypes1.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/diags/examples/IncompatibleTypes1.java	Fri Aug 03 12:48:20 2012 +0100
@@ -21,13 +21,13 @@
  * questions.
  */
 
+// key: compiler.err.prob.found.req
 // key: compiler.misc.infer.no.conforming.instance.exists
-// key: compiler.err.prob.found.req
 
 class IncompatibleTypes1<V> {
-    <T extends Integer & Runnable> IncompatibleTypes1<T> m() {
+    <T> IncompatibleTypes1<Integer> m() {
         return null;
     }
 
-    IncompatibleTypes1<? super String> o = m();
+    IncompatibleTypes1<? extends String> o = m();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/diags/examples/InferNoConformingAssignment.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.apply.symbol.1
+// key: compiler.misc.inconvertible.types
+// key: compiler.misc.infer.no.conforming.assignment.exists
+
+import java.util.*;
+
+class InferNoConformingAssignment {
+    <X extends Number> List<X> m(String s) { return null; }
+    { this.m(1); }
+}
+
--- a/test/tools/javac/diags/examples/InferredDoNotConformToBounds.java	Mon Jul 30 13:34:28 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.misc.inferred.do.not.conform.to.bounds
-// key: compiler.err.cant.apply.diamond.1
-// key: compiler.misc.diamond
-
-class InferredDoNotConformToBounds {
-   static class SuperFoo<X> {}
-   static class Foo<X extends Number> extends SuperFoo<X> {
-       Foo(X x) {}
-   }
-
-   SuperFoo<String> sf1 = new Foo<>("");
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/diags/examples/InferredDoNotConformToEq.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.apply.symbol.1
+// key: compiler.misc.inferred.do.not.conform.to.eq.bounds
+
+import java.util.*;
+
+class InferredDoNotConformToEq {
+    <X> void m(List<X> lx1, List<X> lx2) {}
+    { this.m(Arrays.asList(""), Arrays.asList(1)); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/diags/examples/InferredDoNotConformToLower.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.inferred.do.not.conform.to.lower.bounds
+
+import java.util.*;
+
+class InferredDoNotConformToLower {
+    <X extends Number> List<X> m() { return null; }
+    { List<? super String> lss = this.m(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/diags/examples/InferredDoNotConformToUpper.java	Fri Aug 03 12:48:20 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.apply.symbol.1
+// key: compiler.misc.inferred.do.not.conform.to.upper.bounds
+
+import java.util.*;
+
+class InferredDoNotConformToUpper {
+    <X> void m(X x, List<? super X> lx) {}
+    { this.m("", Arrays.asList(1)); }
+}
--- a/test/tools/javac/diags/examples/WhereCaptured.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/diags/examples/WhereCaptured.java	Fri Aug 03 12:48:20 2012 +0100
@@ -26,8 +26,7 @@
 // key: compiler.misc.where.description.typevar
 // key: compiler.misc.where.typevar
 // key: compiler.err.cant.apply.symbol.1
-// key: compiler.misc.infer.no.conforming.assignment.exists
-// key: compiler.misc.inconvertible.types
+// key: compiler.misc.inferred.do.not.conform.to.eq.bounds
 // key: compiler.misc.captured.type
 // options: -XDdiags=where,simpleNames
 // run: simple
--- a/test/tools/javac/diags/examples/WhereCaptured1.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/diags/examples/WhereCaptured1.java	Fri Aug 03 12:48:20 2012 +0100
@@ -26,8 +26,7 @@
 // key: compiler.misc.where.description.typevar
 // key: compiler.misc.where.typevar
 // key: compiler.err.cant.apply.symbol.1
-// key: compiler.misc.infer.no.conforming.assignment.exists
-// key: compiler.misc.inconvertible.types
+// key: compiler.misc.inferred.do.not.conform.to.eq.bounds
 // key: compiler.misc.captured.type
 // key: compiler.misc.type.null
 // options: -XDdiags=where,simpleNames
--- a/test/tools/javac/generics/7015430/T7015430.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/7015430/T7015430.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,14 +1,14 @@
-T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
+T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
 T7015430.java:41:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
 T7015430.java:50:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
 T7015430.java:50:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
-T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
+T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
 T7015430.java:68:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
 T7015430.java:77:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
 T7015430.java:77:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
 T7015430.java:104:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException>
 T7015430.java:104:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
-T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception>
+T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E>
 T7015430.java:113:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430
 T7015430.java:41:14: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
 T7015430.java:68:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
--- a/test/tools/javac/generics/7151802/T7151802.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/7151802/T7151802.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,5 +1,5 @@
 T7151802.java:14:31: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get1, Z, T7151802.Foo, kindname.class, T7151802
-T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<java.lang.Object>
+T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<Z>
 T7151802.java:22:30: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get3, T7151802.Foo<Z>, T7151802.Foo, kindname.class, T7151802
 T7151802.java:30:36: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get5, compiler.misc.no.args, compiler.misc.no.args, kindname.class, T7151802
 T7151802.java:38:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<java.lang.String>
--- a/test/tools/javac/generics/diamond/neg/Neg06.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/diamond/neg/Neg06.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-Neg06.java:16:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.infer.no.conforming.instance.exists: X, Neg06.CFoo<X>, Neg06.CSuperFoo<java.lang.String>))
+Neg06.java:16:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number))
 1 error
--- a/test/tools/javac/generics/diamond/neg/Neg07.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/diamond/neg/Neg07.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.String, java.lang.Number)
+Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number)
 1 error
--- a/test/tools/javac/generics/diamond/neg/Neg10.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/diamond/neg/Neg10.java	Fri Aug 03 12:48:20 2012 +0100
@@ -5,6 +5,7 @@
  * @summary  Check that 'complex' diamond can infer type that is too specific
  * @author mcimadamore
  * @compile/fail/ref=Neg10.out Neg10.java -XDrawDiagnostics
+ * @compile Neg10.java -XDuseGraphInference -XDrawDiagnostics
  *
  */
 
--- a/test/tools/javac/generics/diamond/neg/Neg10.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/diamond/neg/Neg10.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-Neg10.java:16:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>)
+Neg10.java:17:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>)
 1 error
--- a/test/tools/javac/generics/inference/6315770/T6315770.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6315770/T6315770.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,3 +1,3 @@
 T6315770.java:16:42: compiler.err.prob.found.req: (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable)
-T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>)
+T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer&java.lang.Runnable, java.lang.String)
 2 errors
--- a/test/tools/javac/generics/inference/6611449/T6611449.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6611449/T6611449.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,5 +1,5 @@
-T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S))}
-T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.infer.arg.length.mismatch: T))}
-T6611449.java:20:9: compiler.err.cant.apply.symbol.1: kindname.method, m1, T, int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S)
-T6611449.java:21:9: compiler.err.cant.apply.symbol.1: kindname.method, m2, T,T, int,int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S)
+T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S))}
+T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.infer.arg.length.mismatch: T))}
+T6611449.java:20:9: compiler.err.cant.apply.symbol.1: kindname.method, m1, T, int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S)
+T6611449.java:21:9: compiler.err.cant.apply.symbol.1: kindname.method, m2, T,T, int,int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S)
 4 errors
--- a/test/tools/javac/generics/inference/6638712/T6638712b.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6638712/T6638712b.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: T, T, java.lang.String)
+T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, java.lang.String,java.lang.Object)
 1 error
--- a/test/tools/javac/generics/inference/6638712/T6638712d.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6638712/T6638712d.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-T6638712d.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, U,java.util.List<java.util.List<U>>, int,java.util.List<java.util.List<java.lang.String>>, kindname.class, T6638712d, (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.inconvertible.types: int, java.lang.String))
+T6638712d.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, U,java.util.List<java.util.List<U>>, int,java.util.List<java.util.List<java.lang.String>>, kindname.class, T6638712d, (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.String, java.lang.Integer)
 1 error
--- a/test/tools/javac/generics/inference/6638712/T6638712e.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6638712/T6638712e.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: X, T6638712e.Foo<X,java.lang.String>, T6638712e.Foo<java.lang.Object,java.lang.String>)
+T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Boolean,java.lang.Object)
 1 error
--- a/test/tools/javac/generics/inference/6650759/T6650759m.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/6650759/T6650759m.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<compiler.misc.type.captureof: 1, ? super java.lang.Integer>, java.util.List<? super java.lang.String>)
+T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer, java.lang.String)
 1 error
--- a/test/tools/javac/generics/inference/7086601/T7086601a.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/generics/inference/7086601/T7086601a.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,5 +1,5 @@
-T7086601a.java:20:9: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m1(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m1(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String))}
-T7086601a.java:24:9: compiler.err.cant.apply.symbols: kindname.method, m2, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m2(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m2(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String))}
-T7086601a.java:28:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String)
-T7086601a.java:32:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String)
+T7086601a.java:20:9: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m1(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m1(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String,java.lang.Object))}
+T7086601a.java:24:9: compiler.err.cant.apply.symbols: kindname.method, m2, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m2(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m2(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String,java.lang.Object))}
+T7086601a.java:28:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String,java.lang.Object)
+T7086601a.java:32:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String,java.lang.Object)
 4 errors
--- a/test/tools/javac/lambda/TargetType10.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/lambda/TargetType10.java	Fri Aug 03 12:48:20 2012 +0100
@@ -26,6 +26,7 @@
  * @summary check that wildcards in the target method of a lambda conversion is handled correctly
  * @author  Maurizio Cimadamore
  * @compile/fail/ref=TargetType10.out -XDrawDiagnostics TargetType10.java
+ * @compile -XDuseGraphInference -XDrawDiagnostics TargetType10.java
  */
 
 class TargetType10 {
--- a/test/tools/javac/lambda/TargetType10.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/lambda/TargetType10.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-TargetType10.java:38:11: compiler.err.cant.apply.symbol.1: kindname.method, compose, TargetType10.Function<B,C>,TargetType10.Function<A,? extends B>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType10.Test, (compiler.misc.cyclic.lambda.inference)
+TargetType10.java:39:11: compiler.err.cant.apply.symbol.1: kindname.method, compose, TargetType10.Function<B,C>,TargetType10.Function<A,? extends B>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType10.Test, (compiler.misc.cyclic.lambda.inference)
 1 error
--- a/test/tools/javac/lambda/TargetType20.java	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/lambda/TargetType20.java	Fri Aug 03 12:48:20 2012 +0100
@@ -26,6 +26,7 @@
  * @summary complex case of lambda return type that depends on generic method
  *          inference variable
  * @compile/fail/ref=TargetType20.out -XDrawDiagnostics TargetType20.java
+ * @compile -XDuseGraphInference -XDrawDiagnostics TargetType20.java
  */
 import java.util.*;
 
--- a/test/tools/javac/lambda/TargetType20.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/lambda/TargetType20.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-TargetType20.java:40:10: compiler.err.cant.apply.symbol.1: kindname.method, call, TargetType20.SAM2<Z>,TargetType20.SAM2<Z>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType20.Test, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.infer.incompatible.ret.types.in.lambda: (compiler.misc.inconvertible.types: java.util.ArrayList<java.lang.String>, java.util.List<Z>)))
+TargetType20.java:41:10: compiler.err.cant.apply.symbol.1: kindname.method, call, TargetType20.SAM2<Z>,TargetType20.SAM2<Z>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType20.Test, (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.String, java.lang.String,java.lang.Object)
 1 error
--- a/test/tools/javac/multicatch/Neg07.out	Mon Jul 30 13:34:28 2012 -0700
+++ b/test/tools/javac/multicatch/Neg07.out	Fri Aug 03 12:48:20 2012 +0100
@@ -1,2 +1,2 @@
-Neg07.java:14:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Class<compiler.misc.type.captureof: 1, ? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>)
+Neg07.java:14:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Class<? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>)
 1 error