src/share/classes/com/sun/tools/javac/code/Type.java

changeset 1338
ad2ca2a4ab5e
parent 1326
30c36e23f154
child 1342
1a65d6565b45
     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.

mercurial