1.1 --- a/src/share/classes/com/sun/tools/javac/code/Type.java Tue Sep 25 11:55:34 2012 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Tue Sep 25 11:56:46 2012 +0100 1.3 @@ -30,6 +30,10 @@ 1.4 import com.sun.tools.javac.util.*; 1.5 import com.sun.tools.javac.code.Symbol.*; 1.6 1.7 +import java.util.EnumMap; 1.8 +import java.util.EnumSet; 1.9 +import java.util.Map; 1.10 +import java.util.Set; 1.11 import javax.lang.model.type.*; 1.12 1.13 import static com.sun.tools.javac.code.Flags.*; 1.14 @@ -1168,22 +1172,55 @@ 1.15 } 1.16 } 1.17 1.18 - /** A class for instantiatable variables, for use during type 1.19 - * inference. 1.20 + /** A class for inference variables, for use during method/diamond type 1.21 + * inference. An inference variable has upper/lower bounds and a set 1.22 + * of equality constraints. Such bounds are set during subtyping, type-containment, 1.23 + * type-equality checks, when the types being tested contain inference variables. 1.24 + * A change listener can be attached to an inference variable, to receive notifications 1.25 + * whenever the bounds of an inference variable change. 1.26 */ 1.27 public static class UndetVar extends DelegatedType { 1.28 - public List<Type> lobounds = List.nil(); 1.29 - public List<Type> hibounds = List.nil(); 1.30 - public List<Type> eq = List.nil(); 1.31 + 1.32 + /** Inference variable change listener. The listener method is called 1.33 + * whenever a change to the inference variable's bounds occurs 1.34 + */ 1.35 + public interface UndetVarListener { 1.36 + /** called when some inference variable bounds (of given kinds ibs) change */ 1.37 + void varChanged(UndetVar uv, Set<InferenceBound> ibs); 1.38 + } 1.39 + 1.40 + /** 1.41 + * Inference variable bound kinds 1.42 + */ 1.43 + public enum InferenceBound { 1.44 + /** upper bounds */ 1.45 + UPPER, 1.46 + /** lower bounds */ 1.47 + LOWER, 1.48 + /** equality constraints */ 1.49 + EQ; 1.50 + } 1.51 + 1.52 + /** inference variable bounds */ 1.53 + private Map<InferenceBound, List<Type>> bounds; 1.54 + 1.55 + /** inference variable's inferred type (set from Infer.java) */ 1.56 public Type inst = null; 1.57 1.58 + /** inference variable's change listener */ 1.59 + public UndetVarListener listener = null; 1.60 + 1.61 @Override 1.62 public <R,S> R accept(Type.Visitor<R,S> v, S s) { 1.63 return v.visitUndetVar(this, s); 1.64 } 1.65 1.66 - public UndetVar(Type origin) { 1.67 + public UndetVar(TypeVar origin, Types types) { 1.68 super(UNDETVAR, origin); 1.69 + bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); 1.70 + bounds.put(InferenceBound.UPPER, types.getBounds(origin)); 1.71 + bounds.put(InferenceBound.LOWER, List.<Type>nil()); 1.72 + bounds.put(InferenceBound.EQ, List.<Type>nil()); 1.73 } 1.74 1.75 public String toString() { 1.76 @@ -1195,6 +1232,48 @@ 1.77 if (inst != null) return inst.baseType(); 1.78 else return this; 1.79 } 1.80 + 1.81 + /** get all bounds of a given kind */ 1.82 + public List<Type> getBounds(InferenceBound ib) { 1.83 + return bounds.get(ib); 1.84 + } 1.85 + 1.86 + /** add a bound of a given kind - this might trigger listener notification */ 1.87 + public void addBound(InferenceBound ib, Type bound, Types types) { 1.88 + List<Type> prevBounds = bounds.get(ib); 1.89 + for (Type b : prevBounds) { 1.90 + if (types.isSameType(b, bound)) { 1.91 + return; 1.92 + } 1.93 + } 1.94 + bounds.put(ib, prevBounds.prepend(bound)); 1.95 + notifyChange(EnumSet.of(ib)); 1.96 + } 1.97 + 1.98 + /** replace types in all bounds - this might trigger listener notification */ 1.99 + public void substBounds(List<Type> from, List<Type> to, Types types) { 1.100 + EnumSet<InferenceBound> changed = EnumSet.noneOf(InferenceBound.class); 1.101 + Map<InferenceBound, List<Type>> bounds2 = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); 1.102 + for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { 1.103 + InferenceBound ib = _entry.getKey(); 1.104 + List<Type> prevBounds = _entry.getValue(); 1.105 + List<Type> newBounds = types.subst(prevBounds, from, to); 1.106 + bounds2.put(ib, newBounds); 1.107 + if (prevBounds != newBounds) { 1.108 + changed.add(ib); 1.109 + } 1.110 + } 1.111 + if (!changed.isEmpty()) { 1.112 + bounds = bounds2; 1.113 + notifyChange(changed); 1.114 + } 1.115 + } 1.116 + 1.117 + private void notifyChange(EnumSet<InferenceBound> ibs) { 1.118 + if (listener != null) { 1.119 + listener.varChanged(this, ibs); 1.120 + } 1.121 + } 1.122 } 1.123 1.124 /** Represents VOID or NONE.