1.1 --- a/src/share/classes/com/sun/tools/javac/code/Type.java Tue Feb 05 21:55:41 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Wed Feb 06 14:03:39 2013 +0000 1.3 @@ -1309,6 +1309,9 @@ 1.4 /** inference variable's inferred type (set from Infer.java) */ 1.5 public Type inst = null; 1.6 1.7 + /** number of declared (upper) bounds */ 1.8 + public int declaredCount; 1.9 + 1.10 /** inference variable's change listener */ 1.11 public UndetVarListener listener = null; 1.12 1.13 @@ -1318,13 +1321,11 @@ 1.14 } 1.15 1.16 public UndetVar(TypeVar origin, Types types) { 1.17 - this(origin, types, true); 1.18 - } 1.19 - 1.20 - public UndetVar(TypeVar origin, Types types, boolean includeBounds) { 1.21 super(UNDETVAR, origin); 1.22 bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); 1.23 - bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil()); 1.24 + List<Type> declaredBounds = types.getBounds(origin); 1.25 + declaredCount = declaredBounds.length(); 1.26 + bounds.put(InferenceBound.UPPER, declaredBounds); 1.27 bounds.put(InferenceBound.LOWER, List.<Type>nil()); 1.28 bounds.put(InferenceBound.EQ, List.<Type>nil()); 1.29 } 1.30 @@ -1340,38 +1341,89 @@ 1.31 } 1.32 1.33 /** get all bounds of a given kind */ 1.34 - public List<Type> getBounds(InferenceBound ib) { 1.35 - return bounds.get(ib); 1.36 + public List<Type> getBounds(InferenceBound... ibs) { 1.37 + ListBuffer<Type> buf = ListBuffer.lb(); 1.38 + for (InferenceBound ib : ibs) { 1.39 + buf.appendList(bounds.get(ib)); 1.40 + } 1.41 + return buf.toList(); 1.42 + } 1.43 + 1.44 + /** get the list of declared (upper) bounds */ 1.45 + public List<Type> getDeclaredBounds() { 1.46 + ListBuffer<Type> buf = ListBuffer.lb(); 1.47 + int count = 0; 1.48 + for (Type b : getBounds(InferenceBound.UPPER)) { 1.49 + if (count++ == declaredCount) break; 1.50 + buf.append(b); 1.51 + } 1.52 + return buf.toList(); 1.53 } 1.54 1.55 /** add a bound of a given kind - this might trigger listener notification */ 1.56 public void addBound(InferenceBound ib, Type bound, Types types) { 1.57 + Type bound2 = toTypeVarMap.apply(bound); 1.58 List<Type> prevBounds = bounds.get(ib); 1.59 for (Type b : prevBounds) { 1.60 - if (types.isSameType(b, bound)) { 1.61 - return; 1.62 - } 1.63 + //check for redundancy - use strict version of isSameType on tvars 1.64 + //(as the standard version will lead to false positives w.r.t. clones ivars) 1.65 + if (types.isSameType(b, bound2, true)) return; 1.66 } 1.67 - bounds.put(ib, prevBounds.prepend(bound)); 1.68 + bounds.put(ib, prevBounds.prepend(bound2)); 1.69 notifyChange(EnumSet.of(ib)); 1.70 } 1.71 + //where 1.72 + Type.Mapping toTypeVarMap = new Mapping("toTypeVarMap") { 1.73 + @Override 1.74 + public Type apply(Type t) { 1.75 + if (t.hasTag(UNDETVAR)) { 1.76 + UndetVar uv = (UndetVar)t; 1.77 + return uv.qtype; 1.78 + } else { 1.79 + return t.map(this); 1.80 + } 1.81 + } 1.82 + }; 1.83 1.84 /** replace types in all bounds - this might trigger listener notification */ 1.85 public void substBounds(List<Type> from, List<Type> to, Types types) { 1.86 - EnumSet<InferenceBound> changed = EnumSet.noneOf(InferenceBound.class); 1.87 - Map<InferenceBound, List<Type>> bounds2 = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); 1.88 - for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { 1.89 - InferenceBound ib = _entry.getKey(); 1.90 - List<Type> prevBounds = _entry.getValue(); 1.91 - List<Type> newBounds = types.subst(prevBounds, from, to); 1.92 - bounds2.put(ib, newBounds); 1.93 - if (prevBounds != newBounds) { 1.94 - changed.add(ib); 1.95 + List<Type> instVars = from.diff(to); 1.96 + //if set of instantiated ivars is empty, there's nothing to do! 1.97 + if (instVars.isEmpty()) return; 1.98 + final EnumSet<InferenceBound> boundsChanged = EnumSet.noneOf(InferenceBound.class); 1.99 + UndetVarListener prevListener = listener; 1.100 + try { 1.101 + //setup new listener for keeping track of changed bounds 1.102 + listener = new UndetVarListener() { 1.103 + public void varChanged(UndetVar uv, Set<InferenceBound> ibs) { 1.104 + boundsChanged.addAll(ibs); 1.105 + } 1.106 + }; 1.107 + for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { 1.108 + InferenceBound ib = _entry.getKey(); 1.109 + List<Type> prevBounds = _entry.getValue(); 1.110 + ListBuffer<Type> newBounds = ListBuffer.lb(); 1.111 + ListBuffer<Type> deps = ListBuffer.lb(); 1.112 + //step 1 - re-add bounds that are not dependent on ivars 1.113 + for (Type t : prevBounds) { 1.114 + if (!t.containsAny(instVars)) { 1.115 + newBounds.append(t); 1.116 + } else { 1.117 + deps.append(t); 1.118 + } 1.119 + } 1.120 + //step 2 - replace bounds 1.121 + bounds.put(ib, newBounds.toList()); 1.122 + //step 3 - for each dependency, add new replaced bound 1.123 + for (Type dep : deps) { 1.124 + addBound(ib, types.subst(dep, from, to), types); 1.125 + } 1.126 } 1.127 - } 1.128 - if (!changed.isEmpty()) { 1.129 - bounds = bounds2; 1.130 - notifyChange(changed); 1.131 + } finally { 1.132 + listener = prevListener; 1.133 + if (!boundsChanged.isEmpty()) { 1.134 + notifyChange(boundsChanged); 1.135 + } 1.136 } 1.137 } 1.138