8007463: Cleanup inference related classes
Summary: Make Infer.InferenceContext an inner class; adjust bound replacement logic in Type.UndetVar
Reviewed-by: jjg
--- 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;
+ }
+ });
+ }
+
+ /**
+ * 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;
}
- undetvars = undetvars.tail;
+ });
+ }
+
+ /**
+ * 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);
}