changeset 15705:c4124695db0c

8007463: Cleanup inference related classes Summary: Make Infer.InferenceContext an inner class; adjust bound replacement logic in Type.UndetVar Reviewed-by: jjg
author mcimadamore
date Wed, 06 Feb 2013 14:03:39 +0000
parents 02afd052face
children 37a81a6987ac
files langtools/src/share/classes/com/sun/tools/javac/code/Type.java langtools/src/share/classes/com/sun/tools/javac/code/Types.java langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java langtools/src/share/classes/com/sun/tools/javac/comp/Check.java langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java langtools/src/share/classes/com/sun/tools/javac/util/List.java langtools/test/tools/javac/generics/inference/7154127/T7154127.out langtools/test/tools/javac/lib/DPrinter.java
diffstat 10 files changed, 256 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Feb 06 14:03:39 2013 +0000
@@ -1309,6 +1309,9 @@
         /** inference variable's inferred type (set from Infer.java) */
         public Type inst = null;
 
+        /** number of declared (upper) bounds */
+        public int declaredCount;
+
         /** inference variable's change listener */
         public UndetVarListener listener = null;
 
@@ -1318,13 +1321,11 @@
         }
 
         public UndetVar(TypeVar origin, Types types) {
-            this(origin, types, true);
-        }
-
-        public UndetVar(TypeVar origin, Types types, boolean includeBounds) {
             super(UNDETVAR, origin);
             bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class);
-            bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil());
+            List<Type> declaredBounds = types.getBounds(origin);
+            declaredCount = declaredBounds.length();
+            bounds.put(InferenceBound.UPPER, declaredBounds);
             bounds.put(InferenceBound.LOWER, List.<Type>nil());
             bounds.put(InferenceBound.EQ, List.<Type>nil());
         }
@@ -1340,38 +1341,89 @@
         }
 
         /** get all bounds of a given kind */
-        public List<Type> getBounds(InferenceBound ib) {
-            return bounds.get(ib);
+        public List<Type> getBounds(InferenceBound... ibs) {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            for (InferenceBound ib : ibs) {
+                buf.appendList(bounds.get(ib));
+            }
+            return buf.toList();
+        }
+
+        /** get the list of declared (upper) bounds */
+        public List<Type> getDeclaredBounds() {
+            ListBuffer<Type> buf = ListBuffer.lb();
+            int count = 0;
+            for (Type b : getBounds(InferenceBound.UPPER)) {
+                if (count++ == declaredCount) break;
+                buf.append(b);
+            }
+            return buf.toList();
         }
 
         /** add a bound of a given kind - this might trigger listener notification */
         public void addBound(InferenceBound ib, Type bound, Types types) {
+            Type bound2 = toTypeVarMap.apply(bound);
             List<Type> prevBounds = bounds.get(ib);
             for (Type b : prevBounds) {
-                if (types.isSameType(b, bound)) {
-                    return;
-                }
+                //check for redundancy - use strict version of isSameType on tvars
+                //(as the standard version will lead to false positives w.r.t. clones ivars)
+                if (types.isSameType(b, bound2, true)) return;
             }
-            bounds.put(ib, prevBounds.prepend(bound));
+            bounds.put(ib, prevBounds.prepend(bound2));
             notifyChange(EnumSet.of(ib));
         }
+        //where
+            Type.Mapping toTypeVarMap = new Mapping("toTypeVarMap") {
+                @Override
+                public Type apply(Type t) {
+                    if (t.hasTag(UNDETVAR)) {
+                        UndetVar uv = (UndetVar)t;
+                        return uv.qtype;
+                    } else {
+                        return t.map(this);
+                    }
+                }
+            };
 
         /** 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);
+            List<Type> instVars = from.diff(to);
+            //if set of instantiated ivars is empty, there's nothing to do!
+            if (instVars.isEmpty()) return;
+            final EnumSet<InferenceBound> boundsChanged = EnumSet.noneOf(InferenceBound.class);
+            UndetVarListener prevListener = listener;
+            try {
+                //setup new listener for keeping track of changed bounds
+                listener = new UndetVarListener() {
+                    public void varChanged(UndetVar uv, Set<InferenceBound> ibs) {
+                        boundsChanged.addAll(ibs);
+                    }
+                };
+                for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) {
+                    InferenceBound ib = _entry.getKey();
+                    List<Type> prevBounds = _entry.getValue();
+                    ListBuffer<Type> newBounds = ListBuffer.lb();
+                    ListBuffer<Type> deps = ListBuffer.lb();
+                    //step 1 - re-add bounds that are not dependent on ivars
+                    for (Type t : prevBounds) {
+                        if (!t.containsAny(instVars)) {
+                            newBounds.append(t);
+                        } else {
+                            deps.append(t);
+                        }
+                    }
+                    //step 2 - replace bounds
+                    bounds.put(ib, newBounds.toList());
+                    //step 3 - for each dependency, add new replaced bound
+                    for (Type dep : deps) {
+                        addBound(ib, types.subst(dep, from, to), types);
+                    }
                 }
-            }
-            if (!changed.isEmpty()) {
-                bounds = bounds2;
-                notifyChange(changed);
+            } finally {
+                listener = prevListener;
+                if (!boundsChanged.isEmpty()) {
+                    notifyChange(boundsChanged);
+                }
             }
         }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Feb 06 14:03:39 2013 +0000
@@ -976,9 +976,12 @@
      * lists are of different length, return false.
      */
     public boolean isSameTypes(List<Type> ts, List<Type> ss) {
+        return isSameTypes(ts, ss, false);
+    }
+    public boolean isSameTypes(List<Type> ts, List<Type> ss, boolean strict) {
         while (ts.tail != null && ss.tail != null
                /*inlined: ts.nonEmpty() && ss.nonEmpty()*/ &&
-               isSameType(ts.head, ss.head)) {
+               isSameType(ts.head, ss.head, strict)) {
             ts = ts.tail;
             ss = ss.tail;
         }
@@ -990,10 +993,15 @@
      * Is t the same type as s?
      */
     public boolean isSameType(Type t, Type s) {
-        return isSameType.visit(t, s);
+        return isSameType(t, s, false);
+    }
+    public boolean isSameType(Type t, Type s, boolean strict) {
+        return strict ?
+                isSameTypeStrict.visit(t, s) :
+                isSameTypeLoose.visit(t, s);
     }
     // where
-        private TypeRelation isSameType = new TypeRelation() {
+        abstract class SameTypeVisitor extends TypeRelation {
 
             public Boolean visitType(Type t, Type s) {
                 if (t == s)
@@ -1010,8 +1018,7 @@
                     if (s.tag == TYPEVAR) {
                         //type-substitution does not preserve type-var types
                         //check that type var symbols and bounds are indeed the same
-                        return t.tsym == s.tsym &&
-                                visit(t.getUpperBound(), s.getUpperBound());
+                        return sameTypeVars((TypeVar)t, (TypeVar)s);
                     }
                     else {
                         //special case for s == ? super X, where upper(s) = u
@@ -1026,6 +1033,8 @@
                 }
             }
 
+            abstract boolean sameTypeVars(TypeVar tv1, TypeVar tv2);
+
             @Override
             public Boolean visitWildcardType(WildcardType t, Type s) {
                 if (s.isPartial())
@@ -1060,9 +1069,11 @@
                 }
                 return t.tsym == s.tsym
                     && visit(t.getEnclosingType(), s.getEnclosingType())
-                    && containsTypeEquivalent(t.getTypeArguments(), s.getTypeArguments());
+                    && containsTypes(t.getTypeArguments(), s.getTypeArguments());
             }
 
+            abstract protected boolean containsTypes(List<Type> ts1, List<Type> ts2);
+
             @Override
             public Boolean visitArrayType(ArrayType t, Type s) {
                 if (t == s)
@@ -1115,6 +1126,36 @@
             public Boolean visitErrorType(ErrorType t, Type s) {
                 return true;
             }
+        }
+
+        /**
+         * Standard type-equality relation - type variables are considered
+         * equals if they share the same type symbol.
+         */
+        TypeRelation isSameTypeLoose = new SameTypeVisitor() {
+            @Override
+            boolean sameTypeVars(TypeVar tv1, TypeVar tv2) {
+                return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound());
+            }
+            @Override
+            protected boolean containsTypes(List<Type> ts1, List<Type> ts2) {
+                return containsTypeEquivalent(ts1, ts2);
+            }
+        };
+
+        /**
+         * Strict type-equality relation - type variables are considered
+         * equals if they share the same object identity.
+         */
+        TypeRelation isSameTypeStrict = new SameTypeVisitor() {
+            @Override
+            boolean sameTypeVars(TypeVar tv1, TypeVar tv2) {
+                return tv1 == tv2;
+            }
+            @Override
+            protected boolean containsTypes(List<Type> ts1, List<Type> ts2) {
+                return isSameTypes(ts1, ts2, true);
+            }
         };
     // </editor-fold>
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Feb 06 14:03:39 2013 +0000
@@ -43,7 +43,7 @@
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
-import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
+import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -244,8 +244,8 @@
                     @Override
                     public void typesInferred(InferenceContext inferenceContext) {
                         ResultInfo pendingResult =
-                                    resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
-                        check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult);
+                                    resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
+                        check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
                     }
                 });
                 return tree.type = resultInfo.pt;
@@ -2415,7 +2415,7 @@
                 inferenceContext.addFreeTypeListener(ts, new FreeTypeListener() {
                     @Override
                     public void typesInferred(InferenceContext inferenceContext) {
-                        checkAccessibleTypes(pos, env, inferenceContext, inferenceContext.asInstTypes(ts, types));
+                        checkAccessibleTypes(pos, env, inferenceContext, inferenceContext.asInstTypes(ts));
                     }
                 });
             } else {
@@ -2440,7 +2440,7 @@
             @Override
             public boolean compatible(Type found, Type req, Warner warn) {
                 //return type must be compatible in both current context and assignment context
-                return chk.basicHandler.compatible(found, inferenceContext().asFree(req, types), warn);
+                return chk.basicHandler.compatible(found, inferenceContext().asFree(req), warn);
             }
 
             @Override
@@ -2475,7 +2475,7 @@
         * descriptor.
         */
         private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) {
-            Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
+            Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
 
             //return values have already been checked - but if lambda has no return
             //values, we must ensure that void/value compatibility is correct;
@@ -2487,13 +2487,13 @@
                         diags.fragment("missing.ret.val", returnType)));
             }
 
-            List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes(), types);
+            List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes());
             if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) {
                 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
             }
 
             if (!speculativeAttr) {
-                List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types);
+                List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
                 if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) {
                     log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes);
                 }
@@ -2680,7 +2680,7 @@
 
     @SuppressWarnings("fallthrough")
     void checkReferenceCompatible(JCMemberReference tree, Type descriptor, Type refType, CheckContext checkContext, boolean speculativeAttr) {
-        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
+        Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
 
         Type resType;
         switch (tree.getMode()) {
@@ -2712,7 +2712,7 @@
         }
 
         if (!speculativeAttr) {
-            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types);
+            List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
             if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) {
                 log.error(tree, "incompatible.thrown.types.in.mref", refType.getThrownTypes());
             }
@@ -2728,7 +2728,7 @@
         if (inferenceContext.free(descriptorType)) {
             inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
                 public void typesInferred(InferenceContext inferenceContext) {
-                    setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType, types), inferenceContext);
+                    setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType), inferenceContext);
                 }
             });
         } else {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Feb 06 14:03:39 2013 +0000
@@ -42,7 +42,7 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
-import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
+import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
 
@@ -530,7 +530,7 @@
             inferenceContext.addFreeTypeListener(List.of(req), new FreeTypeListener() {
                 @Override
                 public void typesInferred(InferenceContext inferenceContext) {
-                    checkType(pos, found, inferenceContext.asInstType(req, types), checkContext);
+                    checkType(pos, found, inferenceContext.asInstType(req), checkContext);
                 }
             });
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Wed Feb 06 14:03:39 2013 +0000
@@ -373,8 +373,8 @@
                 if (!progress) {
                     //remove all variables that have already been instantiated
                     //from the list of stuck variables
-                    inferenceContext.solveAny(inferenceContext.freeVarsIn(List.from(stuckVars)), types, infer);
-                    inferenceContext.notifyChange(types);
+                    inferenceContext.solveAny(inferenceContext.freeVarsIn(List.from(stuckVars)));
+                    inferenceContext.notifyChange();
                 }
             }
         }
@@ -383,7 +383,7 @@
          * Class representing a deferred attribution node. It keeps track of
          * a deferred type, along with the expected target type information.
          */
-        class DeferredAttrNode implements Infer.InferenceContext.FreeTypeListener {
+        class DeferredAttrNode implements Infer.FreeTypeListener {
 
             /** underlying deferred type */
             DeferredType dt;
@@ -406,7 +406,7 @@
             @Override
             public void typesInferred(InferenceContext inferenceContext) {
                 stuckVars = List.nil();
-                resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
+                resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
             }
 
             /**
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Feb 06 14:03:39 2013 +0000
@@ -241,7 +241,7 @@
         for (Type t : todo) {
             UndetVar uv = (UndetVar)t;
             TypeVar ct = (TypeVar)uv.inst;
-            ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
+            ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct)));
             if (ct.bound.isErroneous()) {
                 //report inference error if glb fails
                 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
@@ -265,7 +265,7 @@
                                   Resolve.MethodCheck methodCheck,
                                   Warner warn) throws InferenceException {
         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
-        final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
+        final InferenceContext inferenceContext = new InferenceContext(tvars);
         inferenceException.clear();
 
         DeferredAttr.DeferredAttrContext deferredAttrContext =
@@ -288,7 +288,7 @@
 
             checkWithinBounds(inferenceContext, warn);
 
-            mt = (MethodType)inferenceContext.asInstType(mt, types);
+            mt = (MethodType)inferenceContext.asInstType(mt);
 
             List<Type> restvars = inferenceContext.restvars();
 
@@ -299,7 +299,7 @@
                     }
                     instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
                     checkWithinBounds(inferenceContext, warn);
-                    mt = (MethodType)inferenceContext.asInstType(mt, types);
+                    mt = (MethodType)inferenceContext.asInstType(mt);
                     if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
                         log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
                     }
@@ -309,7 +309,7 @@
             // return instantiated version of method type
             return mt;
         } finally {
-            inferenceContext.notifyChange(types);
+            inferenceContext.notifyChange();
         }
     }
     //where
@@ -320,7 +320,7 @@
                     to = mt.getReturnType().isPrimitiveOrVoid() ?
                             mt.getReturnType() : syms.objectType;
                 }
-                Type qtype1 = inferenceContext.asFree(mt.getReturnType(), types);
+                Type qtype1 = inferenceContext.asFree(mt.getReturnType());
                 Warner retWarn = new Warner();
                 if (!resultInfo.checkContext.compatible(qtype1, qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to, retWarn) ||
                         //unchecked conversion is not allowed
@@ -342,9 +342,9 @@
             uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
             checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
             if (!inferenceContext.restvars().contains(uv.qtype)) {
-                Type inst = inferenceContext.asInstType(t, types);
+                Type inst = inferenceContext.asInstType(t);
                 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
-                    if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
+                    if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u), warn)) {
                         reportBoundError(uv, BoundErrorKind.UPPER);
                     }
                 }
@@ -478,7 +478,7 @@
         } else {
             Type formalInterface = funcInterface.tsym.type;
             InferenceContext funcInterfaceContext =
-                    new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
+                    new InferenceContext(funcInterface.tsym.type.getTypeArguments());
             Assert.check(paramTypes != null);
             //get constraints from explicit params (this is done by
             //checking that explicit param types are equal to the ones
@@ -489,7 +489,7 @@
                 return types.createErrorType(funcInterface);
             }
             for (Type p : descParameterTypes) {
-                if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
+                if (!types.isSameType(funcInterfaceContext.asFree(p), paramTypes.head)) {
                     checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
                     return types.createErrorType(funcInterface);
                 }
@@ -498,17 +498,19 @@
             List<Type> actualTypeargs = funcInterface.getTypeArguments();
             for (Type t : funcInterfaceContext.undetvars) {
                 UndetVar uv = (UndetVar)t;
-                minimizeInst(uv, types.noWarnings);
-                if (uv.inst == null &&
-                        Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
-                    maximizeInst(uv, types.noWarnings);
-                }
-                if (uv.inst == null) {
+                if (funcInterfaceContext.boundedVars().contains(uv.qtype)) {
+                    minimizeInst(uv, types.noWarnings);
+                    if (uv.inst == null &&
+                            Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
+                        maximizeInst(uv, types.noWarnings);
+                    }
+                } else {
                     uv.inst = actualTypeargs.head;
                 }
+                Assert.check(uv.inst != null);
                 actualTypeargs = actualTypeargs.tail;
             }
-            Type owntype = funcInterfaceContext.asInstType(formalInterface, types);
+            Type owntype = funcInterfaceContext.asInstType(formalInterface);
             if (!chk.checkValidGenericType(owntype)) {
                 //if the inferred functional interface type is not well-formed,
                 //or if it's not a subtype of the original target, issue an error
@@ -585,23 +587,13 @@
         }
 
     /**
-     * Mapping that turns inference variables into undet vars
-     * (used by inference context)
+     * Functional interface for defining inference callbacks. Certain actions
+     * (i.e. subtyping checks) might need to be redone after all inference variables
+     * have been fixed.
      */
-    class FromTypeVarFun extends Mapping {
-
-        boolean includeBounds;
-
-        FromTypeVarFun(boolean includeBounds) {
-            super("fromTypeVarFunWithBounds");
-            this.includeBounds = includeBounds;
-        }
-
-        public Type apply(Type t) {
-            if (t.hasTag(TYPEVAR)) return new UndetVar((TypeVar)t, types, includeBounds);
-            else return t.map(this);
-        }
-    };
+    interface FreeTypeListener {
+        void typesInferred(InferenceContext inferenceContext);
+    }
 
     /**
      * An inference context keeps track of the set of variables that are free
@@ -611,16 +603,7 @@
      * it can be used as an entry point for performing upper/lower bound inference
      * (see InferenceKind).
      */
-    static 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 FreeTypeListener {
-            void typesInferred(InferenceContext inferenceContext);
-        }
+    class InferenceContext {
 
         /** list of inference vars as undet vars */
         List<Type> undetvars;
@@ -633,10 +616,18 @@
 
         List<FreeTypeListener> freetypeListeners = List.nil();
 
-        public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
-            this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
+        public InferenceContext(List<Type> inferencevars) {
+            this.undetvars = Type.map(inferencevars, fromTypeVarFun);
             this.inferencevars = inferencevars;
         }
+        //where
+            Mapping fromTypeVarFun = new Mapping("fromTypeVarFunWithBounds") {
+                // mapping that turns inference variables into undet vars
+                public Type apply(Type t) {
+                    if (t.hasTag(TYPEVAR)) return new UndetVar((TypeVar)t, types);
+                    else return t.map(this);
+                }
+            };
 
         /**
          * returns the list of free variables (as type-variables) in this
@@ -648,19 +639,51 @@
 
         /**
          * returns the list of uninstantiated variables (as type-variables) in this
-         * inference context (usually called after instantiate())
+         * inference context
          */
         List<Type> restvars() {
-            List<Type> undetvars = this.undetvars;
-            ListBuffer<Type> restvars = ListBuffer.lb();
-            for (Type t : instTypes()) {
-                UndetVar uv = (UndetVar)undetvars.head;
-                if (uv.qtype == t) {
-                    restvars.append(t);
+            return filterVars(new Filter<UndetVar>() {
+                public boolean accepts(UndetVar uv) {
+                    return uv.inst == null;
                 }
-                undetvars = undetvars.tail;
+            });
+        }
+
+        /**
+         * returns the list of instantiated variables (as type-variables) in this
+         * inference context
+         */
+        List<Type> instvars() {
+            return filterVars(new Filter<UndetVar>() {
+                public boolean accepts(UndetVar uv) {
+                    return uv.inst != null;
+                }
+            });
+        }
+
+        /**
+         * Get list of bounded inference variables (where bound is other than
+         * declared bounds).
+         */
+        final List<Type> boundedVars() {
+            return filterVars(new Filter<UndetVar>() {
+                public boolean accepts(UndetVar uv) {
+                    return uv.getBounds(InferenceBound.UPPER)
+                            .diff(uv.getDeclaredBounds())
+                            .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty();
+                }
+            });
+        }
+
+        private List<Type> filterVars(Filter<UndetVar> fu) {
+            ListBuffer<Type> res = ListBuffer.lb();
+            for (Type t : undetvars) {
+                UndetVar uv = (UndetVar)t;
+                if (fu.accepts(uv)) {
+                    res.append(uv.qtype);
+                }
             }
-            return restvars.toList();
+            return res.toList();
         }
 
         /**
@@ -709,14 +732,14 @@
          * undet vars (used ahead of subtyping/compatibility checks to allow propagation
          * of inference constraints).
          */
-        final Type asFree(Type t, Types types) {
+        final Type asFree(Type t) {
             return types.subst(t, inferencevars, undetvars);
         }
 
-        final List<Type> asFree(List<Type> ts, Types types) {
+        final List<Type> asFree(List<Type> ts) {
             ListBuffer<Type> buf = ListBuffer.lb();
             for (Type t : ts) {
-                buf.append(asFree(t, types));
+                buf.append(asFree(t));
             }
             return buf.toList();
         }
@@ -735,14 +758,14 @@
          * 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, Types types) {
+        Type asInstType(Type t) {
             return types.subst(t, inferencevars, instTypes());
         }
 
-        List<Type> asInstTypes(List<Type> ts, Types types) {
+        List<Type> asInstTypes(List<Type> ts) {
             ListBuffer<Type> buf = ListBuffer.lb();
             for (Type t : ts) {
-                buf.append(asInstType(t, types));
+                buf.append(asInstType(t));
             }
             return buf.toList();
         }
@@ -758,7 +781,7 @@
          * Mark the inference context as complete and trigger evaluation
          * of all deferred checks.
          */
-        void notifyChange(Types types) {
+        void notifyChange() {
             InferenceException thrownEx = null;
             for (Map.Entry<FreeTypeListener, List<Type>> entry :
                     new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
@@ -780,22 +803,23 @@
             }
         }
 
-        void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
+        void solveAny(List<Type> varsToSolve) {
             boolean progress = false;
             for (Type t : varsToSolve) {
-                UndetVar uv = (UndetVar)asFree(t, types);
+                UndetVar uv = (UndetVar)asFree(t);
                 if (uv.inst == null) {
-                    infer.minimizeInst(uv, types.noWarnings);
+                    minimizeInst(uv, types.noWarnings);
                     if (uv.inst != null) {
                         progress = true;
                     }
                 }
             }
             if (!progress) {
-                throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
+                throw inferenceException.setMessage("cyclic.inference", varsToSolve);
             }
         }
     }
 
-    final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this, false);
+    final InferenceContext emptyContext = new InferenceContext(List.<Type>nil());
+    // </editor-fold>
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Feb 06 14:03:39 2013 +0000
@@ -35,7 +35,7 @@
 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
 import com.sun.tools.javac.comp.Infer.InferenceContext;
-import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
+import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
@@ -741,7 +741,7 @@
                 inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
                     @Override
                     public void typesInferred(InferenceContext inferenceContext) {
-                        varargsAccessible(env, inferenceContext.asInstType(t, types), inferenceContext);
+                        varargsAccessible(env, inferenceContext.asInstType(t), inferenceContext);
                     }
                 });
             } else {
@@ -785,8 +785,8 @@
 
         public boolean compatible(Type found, Type req, Warner warn) {
             return strict ?
-                    types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req, types), warn) :
-                    types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req, types), warn);
+                    types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req), warn) :
+                    types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req), warn);
         }
 
         public void report(DiagnosticPosition pos, JCDiagnostic details) {
--- a/langtools/src/share/classes/com/sun/tools/javac/util/List.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/List.java	Wed Feb 06 14:03:39 2013 +0000
@@ -96,6 +96,26 @@
         return res.reverse();
     }
 
+    public List<A> intersect(List<A> that) {
+        ListBuffer<A> buf = ListBuffer.lb();
+        for (A el : this) {
+            if (that.contains(el)) {
+                buf.append(el);
+            }
+        }
+        return buf.toList();
+    }
+
+    public List<A> diff(List<A> that) {
+        ListBuffer<A> buf = ListBuffer.lb();
+        for (A el : this) {
+            if (!that.contains(el)) {
+                buf.append(el);
+            }
+        }
+        return buf.toList();
+    }
+
     /** Construct a list consisting of given element.
      */
     public static <A> List<A> of(A x1) {
--- a/langtools/test/tools/javac/generics/inference/7154127/T7154127.out	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/test/tools/javac/generics/inference/7154127/T7154127.out	Wed Feb 06 14:03:39 2013 +0000
@@ -1,2 +1,2 @@
-T7154127.java:19:49: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: Y, T7154127.D,T7154127.B<U>)
+T7154127.java:19:49: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.bounds: Y, T7154127.B<U>,T7154127.D)
 1 error
--- a/langtools/test/tools/javac/lib/DPrinter.java	Tue Feb 05 21:55:41 2013 -0800
+++ b/langtools/test/tools/javac/lib/DPrinter.java	Wed Feb 06 14:03:39 2013 +0000
@@ -1006,6 +1006,7 @@
         public Void visitUndetVar(UndetVar type, Void ignore) {
             for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
                 printList("bounds." + ib, type.getBounds(ib));
+            printInt("declaredCount", type.declaredCount);
             printType("inst", type.inst, Details.SUMMARY);
             return visitDelegatedType(type);
         }