Clover coverage report - DynamicJava Test Coverage (dynamicjava-20130518-r5436)
Coverage timestamp: Sat May 18 2013 03:01:28 CDT
file stats: LOC: 2,774   Methods: 421
NCLOC: 2,122   Classes: 25
 
 Source file Conditionals Statements Methods TOTAL
StandardTypeSystem.java 51.3% 61% 59.6% 58.7%
coverage coverage
 1    package edu.rice.cs.dynamicjava.symbol;
 2   
 3    import java.util.*;
 4   
 5    import edu.rice.cs.plt.tuple.Pair;
 6    import edu.rice.cs.plt.tuple.Option;
 7    import edu.rice.cs.plt.tuple.Wrapper;
 8    import edu.rice.cs.plt.recur.*;
 9    import edu.rice.cs.plt.lambda.*;
 10    import edu.rice.cs.plt.iter.IterUtil;
 11    import edu.rice.cs.plt.collect.CollectUtil;
 12    import edu.rice.cs.plt.collect.Order;
 13    import edu.rice.cs.plt.collect.PredicateSet;
 14    import edu.rice.cs.plt.reflect.JavaVersion;
 15   
 16    import koala.dynamicjava.tree.*;
 17    import koala.dynamicjava.interpreter.TypeUtil;
 18    import koala.dynamicjava.interpreter.NodeProperties;
 19    import edu.rice.cs.dynamicjava.Options;
 20    import edu.rice.cs.dynamicjava.interpreter.EvaluatorException;
 21    import edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator;
 22    import edu.rice.cs.dynamicjava.interpreter.RuntimeBindings;
 23    import edu.rice.cs.dynamicjava.symbol.type.*;
 24   
 25    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 26   
 27    /**
 28    * Abstract parent class for TypeSystems that stick to the standard Java notions of types, conversions,
 29    * class members, etc. Subclasses are responsible for providing core type operations: subtyping, inference,
 30    * well-formedness checking, etc.
 31    */
 32    public abstract class StandardTypeSystem extends TypeSystem {
 33   
 34    private final Options _opt;
 35   
 36    /**
 37    * Whether the most specific method test can use boxing to match parameters' types. This contradicts
 38    * the JLS, but matches javac.
 39    */
 40    private final boolean _boxingInMostSpecific;
 41   
 42    /**
 43    * Whether explicit type arguments (provided by the programmer) should be used if available. If not,
 44    * inference always occurs, ignoring the explicit type arguments.
 45    */
 46    private final boolean _useExplicitTypeArgs;
 47   
 48    /**
 49    * Whether two classes should be considered equal only if they have they are represented by the same
 50    * object. The alternative is to compare full names. (Permissive equality allows for interdependencies,
 51    * for example, between already-compiled classes and source classes.)
 52    */
 53    private final boolean _strictClassEquality;
 54   
 55  2 protected StandardTypeSystem(Options opt, boolean boxingInMostSpecific, boolean useExplicitTypeArgs,
 56    boolean strictClassEquality) {
 57  2 _opt = opt;
 58  2 _boxingInMostSpecific = boxingInMostSpecific;
 59  2 _useExplicitTypeArgs = useExplicitTypeArgs;
 60  2 _strictClassEquality = strictClassEquality;
 61    }
 62   
 63    /** Determine if the type is well-formed. */
 64    public abstract boolean isWellFormed(Type t);
 65   
 66    /** Determine if the given types may be treated as equal. This is recursive, transitive, and symmetric. */
 67    public abstract boolean isEqual(Type t1, Type t2);
 68   
 69    /**
 70    * Determine if {@code subT} is a subtype of {@code superT}. This is a recursive
 71    * (in terms of {@link #isEqual}), transitive relation.
 72    */
 73    public abstract boolean isSubtype(Type subT, Type superT);
 74   
 75    /** Compute a common supertype of the given list of types. */
 76    public abstract Type join(Iterable<? extends Type> ts);
 77   
 78    /** Compute a common subtype of the given list of types. */
 79    public abstract Type meet(Iterable<? extends Type> ts);
 80   
 81    /** Produce types that are bounded by the corresponding type argument and parameter. */
 82    protected abstract Iterable<Type> captureTypeArgs(Iterable<? extends Type> targs,
 83    Iterable<? extends VariableType> params);
 84   
 85    /**
 86    * Top-level entry point for type inference. Produces the set of types corresponding to the given
 87    * type parameters, given that {@code args} were provided where {@code params} were expected
 88    * ({@code args} and {@code params} are assumed to have the same length), and {@code returned} will
 89    * be returned where {@code expected} is expected.
 90    *
 91    * @return A set of inferred type arguments for {@code tparams}, or {@code null} if the parameters
 92    * are overconstrained
 93    */
 94    protected abstract Iterable<Type> inferTypeArguments(Iterable<? extends VariableType> tparams,
 95    Iterable<? extends Type> params, Type returned,
 96    Iterable<? extends Type> args, Option<Type> expected);
 97   
 98   
 99  20460 protected boolean sameClass(ClassType c1, ClassType c2) {
 100  20460 if (_strictClassEquality) { return c1.ofClass().equals(c2.ofClass()); }
 101  0 else { return c1.ofClass().fullName().equals(c2.ofClass().fullName()); }
 102    }
 103   
 104    protected static final Type CLONEABLE_AND_SERIALIZABLE =
 105    new IntersectionType(IterUtil.make(CLONEABLE, SERIALIZABLE));
 106   
 107    // non-static because it depends on makeClassType
 108    private final Type ITERABLE;
 109    {
 110  2 Class<?> c;
 111  2 try { c = Class.forName("java.lang.Iterable"); }
 112  0 catch (ClassNotFoundException e) { c = null; }
 113  2 ITERABLE = (c == null) ? null : makeClassType(SymbolUtil.wrapClass(c));
 114    }
 115   
 116    // non-static because it depends on makeClassType
 117    private final Type COLLECTION = makeClassType(SymbolUtil.wrapClass(Collection.class));
 118   
 119    // non-static because it depends on makeClassType
 120    private final Type ENUM;
 121    {
 122  2 Class<?> c;
 123  2 try { c = Class.forName("java.lang.Enum"); }
 124  0 catch (ClassNotFoundException e) { c = null; }
 125  2 ENUM = (c == null) ? null : makeClassType(SymbolUtil.wrapClass(c));
 126    }
 127   
 128    private final DJClass CLASS = SymbolUtil.wrapClass(Class.class);
 129   
 130  41 public TypePrinter typePrinter() { return new StandardTypePrinter(); }
 131   
 132    /** Determine if {@code t} is a primitive. */
 133  2063 public boolean isPrimitive(Type t) { return t.apply(IS_PRIMITIVE); }
 134   
 135    protected static final TypeVisitorLambda<Boolean> IS_PRIMITIVE = new TypeAbstractVisitor<Boolean>() {
 136  244 public Boolean defaultCase(Type t) { return false; }
 137  1819 @Override public Boolean forPrimitiveType(PrimitiveType t) { return true; }
 138    };
 139   
 140    /** Determine if {@code t} is a reference. */
 141  1518 public boolean isReference(Type t) { return t.apply(IS_REFERENCE); }
 142   
 143    protected static final TypeVisitorLambda<Boolean> IS_REFERENCE = new TypeAbstractVisitor<Boolean>() {
 144  88 public Boolean defaultCase(Type t) { return false; }
 145  1409 @Override public Boolean forReferenceType(ReferenceType t) { return true; }
 146  21 @Override public Boolean forVariableType(VariableType t) { return true; }
 147  0 @Override public Boolean forIntersectionType(IntersectionType t) { return true; }
 148  0 @Override public Boolean forUnionType(UnionType t) { return true; }
 149    };
 150   
 151    /** Determine if {@code t} is an array. */
 152  127 public boolean isArray(Type t) { return t.apply(IS_ARRAY); }
 153   
 154    protected static final TypeVisitorLambda<Boolean> IS_ARRAY = new TypeAbstractVisitor<Boolean>() {
 155    private final Predicate<Type> PRED = LambdaUtil.asPredicate(this);
 156  3 public Boolean defaultCase(Type t) { return false; }
 157  124 @Override public Boolean forArrayType(ArrayType t) { return true; }
 158  0 @Override public Boolean forVariableType(VariableType t) { return t.symbol().upperBound().apply(this); }
 159  0 @Override public Boolean forIntersectionType(IntersectionType t) { return IterUtil.or(t.ofTypes(), PRED); }
 160  0 @Override public Boolean forUnionType(UnionType t) {
 161    // BOTTOM is not an array type
 162  0 return !IterUtil.isEmpty(t.ofTypes()) && IterUtil.and(t.ofTypes(), PRED);
 163    }
 164    };
 165   
 166    /**
 167    * Determine if the type can be used in an enhanced for loop. {@code true} implies that an object of
 168    * type {@code t} has member {@code iterator()}, which returns a {@link java.util.Iterator}.
 169    */
 170  3 public boolean isIterable(Type t) { return isSubtype(t, ITERABLE == null ? COLLECTION : ITERABLE); }
 171   
 172   
 173    /**
 174    * Determine if an object with type {@code t} is enumerable (and so can be used as the selector of a
 175    * {@code switch} statement)
 176    */
 177  0 public boolean isEnum(Type t) { return ENUM != null && isSubtype(t, ENUM); }
 178   
 179    /** Determine if the type is available at runtime (via a {@link Class} object) */
 180  12 public boolean isReifiable(Type t) { return t.apply(IS_REIFIABLE); }
 181   
 182    // cannot be defined statically, because it relies on the definition of non-static "IS_UNBOUNDED_WILDCARD"
 183    private final TypeVisitorLambda<Boolean> IS_REIFIABLE = new TypeAbstractVisitor<Boolean>() {
 184   
 185  0 public Boolean defaultCase(Type t) { return false; }
 186  5 @Override public Boolean forPrimitiveType(PrimitiveType t) { return true; }
 187  0 @Override public Boolean forNullType(NullType t) { return true; }
 188  0 @Override public Boolean forArrayType(ArrayType t) { return t.ofType().apply(this); }
 189  7 @Override public Boolean forSimpleClassType(SimpleClassType t) { return true; }
 190  0 @Override public Boolean forRawClassType(RawClassType t) { return true; }
 191  0 @Override public Boolean forVoidType(VoidType t) { return true; }
 192   
 193  0 @Override public Boolean forParameterizedClassType (ParameterizedClassType t) {
 194  0 for (Type targ : t.typeArguments()) {
 195  0 if (!targ.apply(IS_UNBOUNDED_WILDCARD)) { return false; }
 196    }
 197  0 return true;
 198    }
 199    };
 200   
 201    // cannot be defined statically, because it relies on the definition of non-static "isEqual"
 202    private final TypeVisitorLambda<Boolean> IS_UNBOUNDED_WILDCARD = new TypeAbstractVisitor<Boolean>() {
 203  0 public Boolean defaultCase(Type t) { return false; }
 204  0 @Override public Boolean forWildcard(Wildcard t) {
 205  0 return isEqual(t.symbol().upperBound(), OBJECT) && isEqual(t.symbol().lowerBound(), NULL);
 206    }
 207    };
 208   
 209    /**
 210    * Determine if there exist values whose most specific type is {@code t} (ignoring
 211    * constructor-accessibility issues). (Note that this implies that {@code t} is captured.)
 212    */
 213  483 public boolean isConcrete(Type t) { return t.apply(IS_CONCRETE); }
 214   
 215    private static final TypeVisitorLambda<Boolean> IS_CONCRETE = new TypeAbstractVisitor<Boolean>() {
 216  0 public Boolean defaultCase(Type t) { return false; }
 217  0 @Override public Boolean forPrimitiveType(PrimitiveType t) { return true; }
 218  0 @Override public Boolean forArrayType(ArrayType t) { return true; }
 219  316 @Override public Boolean forSimpleClassType(SimpleClassType t) { return isConcreteClass(t.ofClass()); }
 220  0 @Override public Boolean forRawClassType(RawClassType t) { return isConcreteClass(t.ofClass()); }
 221   
 222  167 @Override public Boolean forParameterizedClassType(ParameterizedClassType t) {
 223  0 if (!isConcreteClass(t.ofClass())) { return false; }
 224  167 for (Type targ : t.typeArguments()) {
 225  0 if (targ instanceof Wildcard) { return false; }
 226    }
 227  167 return true;
 228    }
 229   
 230  483 private boolean isConcreteClass(DJClass c) {
 231  483 return !c.isInterface() && !c.isAbstract();
 232    }
 233    };
 234   
 235  483 public Option<Type> dynamicallyEnclosingType(Type t) { return t.apply(DYNAMICALLY_ENCLOSING); }
 236   
 237    private static final TypeVisitorLambda<Option<Type>> DYNAMICALLY_ENCLOSING =
 238    new TypeAbstractVisitor<Option<Type>>() {
 239  0 public Option<Type> defaultCase(Type t) { return Option.none(); }
 240   
 241  483 @Override public Option<Type> forClassType(ClassType t) {
 242  483 return Option.<Type>wrap(SymbolUtil.dynamicOuterClassType(t));
 243    }
 244    };
 245   
 246    /** Determine if {@code t} is valid in the {@code extends} clause of a class definition */
 247  0 public boolean isExtendable(Type t) { return t.apply(IS_EXTENDABLE); }
 248   
 249    private static final TypeVisitorLambda<Boolean> IS_EXTENDABLE = new TypeAbstractVisitor<Boolean>() {
 250  0 public Boolean defaultCase(Type t) { return false; }
 251   
 252  0 @Override public Boolean forClassType(ClassType t) {
 253  0 return !t.ofClass().isInterface() && !t.ofClass().isFinal();
 254    }
 255    };
 256   
 257   
 258    /** Determine if {@code t} is valid in the {@code implements} clause of a class definition */
 259  0 public boolean isImplementable(Type t) { return t.apply(IS_IMPLEMENTABLE); }
 260   
 261    private static final TypeVisitorLambda<Boolean> IS_IMPLEMENTABLE = new TypeAbstractVisitor<Boolean>() {
 262  0 public Boolean defaultCase(Type t) { return false; }
 263  0 @Override public Boolean forClassType(ClassType t) { return t.ofClass().isInterface(); }
 264    };
 265   
 266   
 267    /** Test whether a variable is reachable from a type. */
 268  14 protected boolean containsVar(Type t, final VariableType var) {
 269  14 return containsAnyVar(t, Collections.singleton(var));
 270    }
 271   
 272    /** Test whether any of the given variables is reachable from a type. */
 273  14 protected boolean containsAnyVar(Type t, final Set<? extends VariableType> vars) {
 274  14 return t.apply(new TypeAbstractVisitor<Boolean>() {
 275    private final RecursionStack<Type> _stack = new RecursionStack<Type>(Wrapper.<Type>factory());
 276  0 public Boolean defaultCase(Type t) { return false; }
 277  0 @Override public Boolean forArrayType(ArrayType t) { return t.ofType().apply(this); }
 278  0 @Override public Boolean forParameterizedClassType(ParameterizedClassType t) {
 279  0 return checkList(t.typeArguments());
 280    }
 281  0 @Override public Boolean forBoundType(BoundType t) { return checkList(t.ofTypes()); }
 282  14 @Override public Boolean forVariableType(VariableType t) {
 283  14 return vars.contains(t) || checkBoundedSymbol(t, t.symbol());
 284    }
 285  0 @Override public Boolean forWildcard(Wildcard w) { return checkBoundedSymbol(w, w.symbol()); }
 286   
 287  0 private Boolean checkList(Iterable<? extends Type> types) {
 288  0 for (Type t : types) {
 289  0 if (t.apply(this)) { return true; }
 290    }
 291  0 return false;
 292    }
 293   
 294  0 private Boolean checkBoundedSymbol(Type t, final BoundedSymbol s) {
 295  0 final TypeVisitor<Boolean> visitor = this; // handles this shadowing
 296  0 Thunk<Boolean> handleBounds = new Thunk<Boolean>() {
 297  0 public Boolean value() {
 298  0 return s.lowerBound().apply(visitor) || s.upperBound().apply(visitor);
 299    }
 300    };
 301  0 return _stack.apply(handleBounds, false, t);
 302    }
 303   
 304    });
 305    }
 306   
 307   
 308    /** Whether two types are known to be disjoint. (Standard version is implicitly defined in JLS 5.5.) */
 309  0 public boolean isDisjoint(final Type s, final Type t) {
 310    // By default, returns null for arrays and classes
 311    abstract class Visitor extends TypeAbstractVisitor<Boolean> {
 312    private final Type _other;
 313  0 public Visitor(Type other) { _other = other; }
 314    public abstract boolean recur(Type that);
 315  0 @Override public Boolean forPrimitiveType(PrimitiveType that) {
 316  0 return !isSubtype(that, _other) && !isSubtype(_other, that);
 317    }
 318  0 @Override public Boolean forNullType(NullType that) {
 319  0 return !isSubtype(that, _other);
 320    }
 321  0 @Override public Boolean forArrayType(ArrayType that) { return null; }
 322  0 @Override public Boolean forClassType(ClassType that) { return null; }
 323  0 @Override public Boolean forIntersectionType(IntersectionType that) {
 324  0 for (Type elt : that.ofTypes()) { if (recur(elt)) return true; }
 325  0 return false;
 326    }
 327  0 @Override public Boolean forUnionType(UnionType that) {
 328  0 for (Type elt : that.ofTypes()) { if (!recur(elt)) return false; }
 329  0 return true;
 330    }
 331  0 @Override public Boolean forVariableType(VariableType that) {
 332    // TODO: to be correct, we would need to recur (checked by a RecursionStack)
 333  0 return false;
 334    }
 335  0 @Override public Boolean forTopType(TopType s) { return false; }
 336  0 @Override public Boolean forBottomType(BottomType s) { return true; }
 337    }
 338   
 339  0 Boolean sResult = s.apply(new Visitor(t) {
 340  0 public boolean recur(Type that) { return isDisjoint(that, t); }
 341    });
 342  0 if (sResult != null) { return sResult; }
 343    else {
 344  0 return t.apply(new Visitor(s) {
 345  0 public boolean recur(Type that) { return isDisjoint(s, that); }
 346  0 @Override public Boolean forArrayType(ArrayType t) {
 347  0 if (s instanceof ArrayType) { return isDisjoint(((ArrayType) s).ofType(), t.ofType()); }
 348  0 else { return !isSubtype(t, s); }
 349    }
 350  0 @Override public Boolean forClassType(ClassType t) {
 351  0 if (s instanceof ArrayType) { return !isSubtype(s, t); }
 352    else {
 353  0 ClassType sAsClass = (ClassType) s;
 354  0 if (sAsClass.ofClass().isFinal() || t.ofClass().isFinal() ||
 355    (!sAsClass.ofClass().isInterface() && !t.ofClass().isInterface())) {
 356    // either one of them is a final class or both are non-final classes
 357  0 if (!isSubtype(s, erase(t)) && !isSubtype(t, erase(s))) { return true; }
 358    }
 359    // TODO: The JLS also checks for disjoint type arguments (comparing *all* common superclasses)
 360  0 return false;
 361    }
 362    }
 363    });
 364    }
 365    }
 366   
 367    /** Determine if {@link #assign} would succeed given a non-constant expression of the given type */
 368  373 public boolean isAssignable(Type target, Type expT) {
 369    // TODO: Handle unchecked warnings -- perhaps at the call site
 370  373 try {
 371  373 Expression e = TypeUtil.makeEmptyExpression();
 372  373 NodeProperties.setType(e, expT);
 373  373 assign(target, e);
 374  190 return true;
 375    }
 376  183 catch (UnsupportedConversionException e) { return false; }
 377    }
 378   
 379    /** Determine if {@link #assign} would succeed given a constant expression of the given type and value */
 380  0 public boolean isAssignable(Type target, Type expT, Object expValue) {
 381    // TODO: Handle unchecked warnings -- perhaps at the call site
 382  0 try {
 383  0 Expression e = TypeUtil.makeEmptyExpression();
 384  0 NodeProperties.setType(e, expT);
 385  0 NodeProperties.setValue(e, expValue);
 386  0 assign(target, e);
 387  0 return true;
 388    }
 389  0 catch (UnsupportedConversionException e) { return false; }
 390    }
 391   
 392  16 public boolean isPrimitiveConvertible(Type t) {
 393  16 return isPrimitive(t) ||
 394    (!_opt.prohibitBoxing() && !isSubtype(t, NULL) &&
 395    (isSubtype(t, BOOLEAN_CLASS) ||
 396    isSubtype(t, CHARACTER_CLASS) ||
 397    isSubtype(t, BYTE_CLASS) ||
 398    isSubtype(t, SHORT_CLASS) ||
 399    isSubtype(t, INTEGER_CLASS) ||
 400    isSubtype(t, LONG_CLASS) ||
 401    isSubtype(t, FLOAT_CLASS) ||
 402    isSubtype(t, DOUBLE_CLASS)));
 403    }
 404   
 405   
 406  55 public boolean isReferenceConvertible(Type t) {
 407  55 return isReference(t) || !_opt.prohibitBoxing() && t instanceof PrimitiveType;
 408    }
 409   
 410   
 411  0 public Type immediateSuperclass(Type t) {
 412  0 if (t instanceof ClassType) { return ((ClassType) t).ofClass().immediateSuperclass(); }
 413  0 else { return null; }
 414    }
 415   
 416  2137 public Type capture(Type t) { return t.apply(CAPTURE); }
 417   
 418    // cannot be defined statically, because it relies on the definition of non-static "capture"
 419    private final TypeVisitorLambda<Type> CAPTURE = new TypeAbstractVisitor<Type>() {
 420  1793 public Type defaultCase(Type t) { return t; }
 421  144 public Type forVarargArrayType(VarargArrayType t) { return new SimpleArrayType(t.ofType()); }
 422  200 @Override public Type forParameterizedClassType(ParameterizedClassType t) { return capture(t); }
 423    };
 424   
 425  3402 protected ParameterizedClassType capture(ParameterizedClassType t) {
 426  3402 boolean ground = true; // optimization: simply return non-wildcard cases
 427  3402 for (Type arg : t.typeArguments()) {
 428  284 if (arg instanceof Wildcard) { ground = false; break; }
 429    }
 430  3118 if (ground) { return t; }
 431    else {
 432  284 Iterable<VariableType> params = SymbolUtil.allTypeParameters(t.ofClass());
 433  284 Iterable<Type> captureArgs = captureTypeArgs(t.typeArguments(), params);
 434  284 return new ParameterizedClassType(t.ofClass(), captureArgs);
 435    }
 436    }
 437   
 438    /**
 439    * Compute the erased type of {@code t}. The result is guaranteed to be reifiable (according
 440    * to {@link #isReifiable}) and a supertype of {@code t}.
 441    */
 442  5187 public Type erase(Type t) { return t.apply(ERASE); }
 443   
 444    private static final TypeVisitorLambda<Type> ERASE = new TypeAbstractVisitor<Type>() {
 445  1852 public Type defaultCase(Type t) { return t; }
 446   
 447  0 @Override public Type forNullType(NullType t) { return OBJECT; }
 448   
 449  28 @Override public Type forSimpleArrayType(SimpleArrayType t) {
 450  28 Type newElementType = t.ofType().apply(this);
 451  28 return (t.ofType() == newElementType) ? t : new SimpleArrayType(newElementType);
 452    }
 453   
 454  56 @Override public Type forVarargArrayType(VarargArrayType t) {
 455  56 Type newElementType = t.ofType().apply(this);
 456  56 return (t.ofType() == newElementType) ? t : new VarargArrayType(newElementType);
 457    }
 458   
 459  8300 @Override public Type forParameterizedClassType(ParameterizedClassType t) {
 460  8300 return new RawClassType(t.ofClass());
 461    }
 462   
 463  255 @Override public Type forVariableType(VariableType t) { return t.symbol().upperBound().apply(this); }
 464   
 465  0 @Override public Type forIntersectionType(IntersectionType t) {
 466  0 if (IterUtil.isEmpty(t.ofTypes())) { return OBJECT; }
 467  0 else { return IterUtil.first(t.ofTypes()).apply(this); }
 468    }
 469   
 470  8 @Override public Type forUnionType(UnionType t) {
 471    // TODO: improve this result by performing a join on the erased class hierarchy
 472  8 return OBJECT;
 473    }
 474   
 475  0 @Override public Type forWildcard(Wildcard t) { throw new IllegalArgumentException(); }
 476  0 @Override public Type forTopType(TopType t) { throw new IllegalArgumentException(); }
 477  0 @Override public Type forBottomType(BottomType t) { throw new IllegalArgumentException(); }
 478    };
 479   
 480    /**
 481    * Determine the class corresponding to the erasure of {@code t}, or {@code null} if no such class object
 482    * exists. To prevent over-eager loading of user-defined classes, computation of the result
 483    * is delayed by wrapping it in a thunk. (A DJClass return type would be incorrect, as there's no such
 484    * thing (for example) as an array DJClass.)
 485    */
 486  1234 public Thunk<Class<?>> erasedClass(Type t) { return t.apply(ERASED_CLASS); }
 487   
 488    private static final TypeVisitorLambda<Thunk<Class<?>>> ERASED_CLASS = new TypeVisitorLambda<Thunk<Class<?>>>() {
 489  50 public Thunk<Class<?>> forBooleanType(BooleanType t) { return LambdaUtil.<Class<?>>valueLambda(boolean.class); }
 490  9 public Thunk<Class<?>> forCharType(CharType t) { return LambdaUtil.<Class<?>>valueLambda(char.class); }
 491  14 public Thunk<Class<?>> forByteType(ByteType t) { return LambdaUtil.<Class<?>>valueLambda(byte.class); }
 492  14 public Thunk<Class<?>> forShortType(ShortType t) { return LambdaUtil.<Class<?>>valueLambda(short.class); }
 493  327 public Thunk<Class<?>> forIntType(IntType t) { return LambdaUtil.<Class<?>>valueLambda(int.class); }
 494  6 public Thunk<Class<?>> forLongType(LongType t) { return LambdaUtil.<Class<?>>valueLambda(long.class); }
 495  16 public Thunk<Class<?>> forFloatType(FloatType t) { return LambdaUtil.<Class<?>>valueLambda(float.class); }
 496  11 public Thunk<Class<?>> forDoubleType(DoubleType t) { return LambdaUtil.<Class<?>>valueLambda(double.class); }
 497  0 public Thunk<Class<?>> forNullType(NullType t) { return forSimpleClassType(OBJECT); }
 498   
 499  33 public Thunk<Class<?>> forSimpleArrayType(SimpleArrayType t) {
 500  33 Thunk<Class<?>> elementType = t.ofType().apply(this);
 501  33 return (elementType == null) ? null : SymbolUtil.arrayClassThunk(elementType);
 502    }
 503   
 504  44 public Thunk<Class<?>> forVarargArrayType(VarargArrayType t) {
 505  44 Thunk<Class<?>> elementType = t.ofType().apply(this);
 506  44 return (elementType == null) ? null : SymbolUtil.arrayClassThunk(elementType);
 507    }
 508   
 509  340 public Thunk<Class<?>> forSimpleClassType(SimpleClassType t) { return wrapDJClass(t.ofClass()); }
 510   
 511  1 public Thunk<Class<?>> forRawClassType(RawClassType t) { return wrapDJClass(t.ofClass()); }
 512   
 513  239 public Thunk<Class<?>> forParameterizedClassType(ParameterizedClassType t) {
 514  239 return wrapDJClass(t.ofClass());
 515    }
 516   
 517  55 public Thunk<Class<?>> forVariableType(VariableType t) {
 518  55 return t.symbol().upperBound().apply(this);
 519    }
 520   
 521  0 public Thunk<Class<?>> forIntersectionType(IntersectionType t) {
 522  0 Iterator<? extends Type> sups = t.ofTypes().iterator();
 523  0 if (!sups.hasNext()) { return null; }
 524  0 else { return sups.next().apply(this); }
 525    }
 526   
 527  0 public Thunk<Class<?>> forUnionType(UnionType t) { return forSimpleClassType(OBJECT); }
 528   
 529  0 public Thunk<Class<?>> forWildcard(Wildcard t) { throw new IllegalArgumentException(); }
 530  207 public Thunk<Class<?>> forVoidType(VoidType t) { return LambdaUtil.<Class<?>>valueLambda(void.class); }
 531  0 public Thunk<Class<?>> forTopType(TopType t) { throw new IllegalArgumentException(); }
 532  0 public Thunk<Class<?>> forBottomType(BottomType t) { throw new IllegalArgumentException(); }
 533   
 534  580 private Thunk<Class<?>> wrapDJClass(final DJClass c) {
 535  580 return new Thunk<Class<?>>() {
 536  335 public Class<?> value() { return c.load(); }
 537    };
 538    }
 539   
 540    };
 541   
 542    /** Convert a raw class type to its wildcard-parameterized equivalent. */
 543  92 protected ParameterizedClassType parameterize(final RawClassType t) {
 544  92 Iterable<VariableType> tparams = SymbolUtil.allTypeParameters(t.ofClass());
 545  92 return new ParameterizedClassType(t.ofClass(), IterUtil.mapSnapshot(tparams, new Lambda<VariableType, Type>() {
 546  92 public Type value(VariableType param) {
 547    // identity is determined by t and param -- result should be identical when repeatedly invoked
 548  92 return new Wildcard(new BoundedSymbol(Pair.make(t, param), OBJECT, NULL));
 549    }
 550    }));
 551    }
 552   
 553    /**
 554    * @return The type of the Class object associated with t (for example, (informally)
 555    * {@code reflectionClassOf(java.lang.Integer) = Class<Integer>}).
 556    */
 557  14 public Type reflectionClassOf(Type t) {
 558  0 if (IterUtil.isEmpty(SymbolUtil.allTypeParameters(CLASS))) { return makeClassType(CLASS); }
 559    else {
 560  14 try { return makeClassType(CLASS, IterUtil.make(t)); }
 561    catch (InvalidTypeArgumentException e) {
 562  0 throw new RuntimeException("java.lang.Class has unexpected type parameter(s)");
 563    }
 564    }
 565    }
 566   
 567    /**
 568    * Determine the element type of the given array type. Assumes {@code t} is an array type (according to
 569    * {@link #isArray}).
 570    */
 571  124 public Type arrayElementType(Type t) {
 572  124 return t.apply(ARRAY_ELEMENT_TYPE);
 573    }
 574   
 575    // not defined statically because it relies on non-static meet() and join()
 576    private final TypeVisitorLambda<Type> ARRAY_ELEMENT_TYPE = new TypeAbstractVisitor<Type>() {
 577  0 public Type defaultCase(Type t) { throw new IllegalArgumentException(); }
 578  124 @Override public Type forArrayType(ArrayType t) { return t.ofType(); }
 579  0 @Override public Type forVariableType(VariableType t) { return t.symbol().upperBound().apply(this); }
 580  0 @Override public Type forIntersectionType(IntersectionType t) {
 581    // at least one element has an array type
 582  0 return meet(IterUtil.map(t.ofTypes(), new Lambda<Type, Type>() {
 583  0 public Type value(Type arrayT) {
 584  0 return arrayT.apply(IS_ARRAY) ? arrayT.apply(ARRAY_ELEMENT_TYPE) : TOP;
 585    }
 586    }));
 587    }
 588  0 @Override public Type forUnionType(UnionType t) {
 589    // there is at least one element, and all have array types
 590  0 return join(IterUtil.map(t.ofTypes(), this));
 591    }
 592    };
 593   
 594   
 595    protected static class SubstitutionMap {
 596    private Map<VariableType, Type> _sigma;
 597    private Iterable<? extends VariableType> _vars;
 598    private Iterable<? extends Type> _values;
 599   
 600    public static final SubstitutionMap EMPTY = new SubstitutionMap(IterUtil.<VariableType>empty(),
 601    EMPTY_TYPE_ITERABLE);
 602   
 603  6029 public SubstitutionMap(Iterable<? extends VariableType> vars, Iterable<? extends Type> values) {
 604  6029 _sigma = null;
 605  6029 _vars = vars;
 606  6029 _values = values;
 607    }
 608   
 609  0 public SubstitutionMap(Map<? extends VariableType, ? extends Type> map) {
 610    // make a copy to prevent mutation
 611  0 _sigma = new HashMap<VariableType, Type>(map);
 612    }
 613   
 614  10206 public boolean isEmpty() {
 615  9578 if (_sigma == null) { return IterUtil.isEmpty(_vars); }
 616  628 else { return _sigma.isEmpty(); }
 617    }
 618   
 619  2677 public Type get(VariableType v) {
 620  2470 if (_sigma == null) { initSigma(); }
 621  2677 return _sigma.get(v);
 622    }
 623   
 624    // Initialize the map lazily, because in same cases it may not be used at all.
 625  2470 private void initSigma() {
 626  2470 _sigma = new HashMap<VariableType, Type>();
 627  2470 for (Pair<VariableType, Type> pair : IterUtil.zip(_vars, _values)) {
 628  2470 _sigma.put(pair.first(), pair.second());
 629    }
 630  2470 _vars = null;
 631  2470 _values = null;
 632    }
 633    }
 634   
 635    /**
 636    * Assumes each paramater is a unique variable, and that the length of params
 637    * is consistent with the length of args.
 638    */
 639  89 protected Type substitute(Type t, Iterable<? extends VariableType> params, Iterable<? extends Type> args) {
 640  89 return substitute(t, new SubstitutionMap(params, args));
 641    }
 642   
 643  0 protected Type substitute(Type t, Map<? extends VariableType, ? extends Type> map) {
 644  0 return substitute(t, new SubstitutionMap(map));
 645    }
 646   
 647  6083 protected Type substitute(Type t, final SubstitutionMap sigma) {
 648  267 if (sigma.isEmpty()) { return t; }
 649    else {
 650  5816 final PrecomputedRecursionStack<Type, Type> stack = PrecomputedRecursionStack.make();
 651   
 652  5816 return t.apply(new TypeUpdateVisitor() {
 653   
 654  2677 @Override public Type forVariableType(VariableType t) {
 655  2677 Type result = sigma.get(t);
 656  2677 return (result == null) ? t : result;
 657    }
 658   
 659  20 @Override public Type forWildcard(final Wildcard t) {
 660  20 final Wildcard newWildcard = new Wildcard(new BoundedSymbol(new Object()));
 661  20 Thunk<Type> substituteBounds = new Thunk<Type>() {
 662  20 public Type value() {
 663  20 BoundedSymbol bounds = t.symbol();
 664  20 Type newUpper = recur(bounds.upperBound());
 665  20 Type newLower = recur(bounds.lowerBound());
 666  13 if (newUpper == bounds.upperBound() && newLower == bounds.lowerBound()) { return t; }
 667    else {
 668  7 newWildcard.symbol().initializeUpperBound(newUpper);
 669  7 newWildcard.symbol().initializeLowerBound(newLower);
 670  7 return newWildcard;
 671    }
 672    }
 673    };
 674  20 return stack.apply(substituteBounds, newWildcard, t);
 675    }
 676   
 677    });
 678    }
 679    }
 680   
 681  2714 private Iterable<? extends Type> substitute(Iterable<? extends Type> ts,
 682    Iterable<? extends VariableType> vars,
 683    Iterable<? extends Type> values) {
 684  2714 return substitute(ts, new SubstitutionMap(vars, values));
 685    }
 686   
 687  4123 private Iterable<? extends Type> substitute(Iterable<? extends Type> ts, final SubstitutionMap sigma) {
 688  1014 if (sigma.isEmpty()) { return ts; }
 689    else {
 690  3109 return IterUtil.mapSnapshot(ts, new Lambda<Type, Type>() {
 691  3175 public Type value(Type t) { return substitute(t, sigma); }
 692    });
 693    }
 694    }
 695   
 696    /**
 697    * Create a {@link SimpleClassType} or {@link RawClassType} corresponding to the given class.
 698    */
 699  1324 public ClassType makeClassType(DJClass c) {
 700  1316 if (IterUtil.isEmpty(SymbolUtil.allTypeParameters(c))) { return new SimpleClassType(c); }
 701  8 else { return new RawClassType(c); }
 702    }
 703   
 704    /**
 705    * Create a {@link SimpleClassType}, {@link RawClassType}, or {@link ParameterizedClassType}
 706    * corresponding to the given class with given type arguments. If {@code args} is nonempty,
 707    * the result must be a {@code ParameterizedClassType} (or an error must occur).
 708    *
 709    * @param c The class to be instantiated
 710    * @param args The type arguments for {@code c}
 711    * @throws InvalidTypeArgumentException If the arguments do not correspond to the formal parameters of
 712    * {@code c} (bounds are not checked, so the result may not be
 713    * well-formed).
 714    */
 715  521 public ClassType makeClassType(DJClass c, Iterable<? extends Type> args) throws InvalidTypeArgumentException {
 716  0 if (IterUtil.isEmpty(args)) { return makeClassType(c); }
 717    else {
 718  521 Iterable<VariableType> params = SymbolUtil.allTypeParameters(c);
 719  0 if (IterUtil.sizeOf(params) != IterUtil.sizeOf(args)) { throw new InvalidTypeArgumentException(); }
 720    else {
 721  521 ParameterizedClassType result = new ParameterizedClassType(c, args);
 722  521 return result;
 723    }
 724    }
 725    }
 726   
 727   
 728    /**
 729    * Convert the expression to a primitive. The result is guaranteed to have a primitive type as its
 730    * TYPE property (according to {@link #isPrimitive}).
 731    *
 732    * @param e A typed expression
 733    * @return A typed expression equivalent to {@code e} that has a primitive type
 734    * @throws UnsupportedConversionException If the expression cannot be converted to a primitive
 735    */
 736  1768 public Expression makePrimitive(Expression e) throws UnsupportedConversionException {
 737  1768 Type t = NodeProperties.getType(e);
 738  1758 if (isPrimitive(t)) { return e; }
 739  0 else if (_opt.prohibitBoxing()) { throw new UnsupportedConversionException(); }
 740    // Note: The spec is not clear about whether a *subtype* (such as a variable) can
 741    // be unboxed. We allow it here unless the type is null, because that seems
 742    // like the correct approach.
 743  1 else if (isSubtype(t, NULL)) { throw new UnsupportedConversionException(); }
 744  1 else if (isSubtype(t, BOOLEAN_CLASS)) { return unbox(e, "booleanValue"); }
 745  1 else if (isSubtype(t, CHARACTER_CLASS)) { return unbox(e, "charValue"); }
 746  1 else if (isSubtype(t, BYTE_CLASS)) { return unbox(e, "byteValue"); }
 747  1 else if (isSubtype(t, SHORT_CLASS)) { return unbox(e, "shortValue"); }
 748  1 else if (isSubtype(t, INTEGER_CLASS)) { return unbox(e, "intValue"); }
 749  1 else if (isSubtype(t, LONG_CLASS)) { return unbox(e, "longValue"); }
 750  1 else if (isSubtype(t, FLOAT_CLASS)) { return unbox(e, "floatValue"); }
 751  1 else if (isSubtype(t, DOUBLE_CLASS)) { return unbox(e, "doubleValue"); }
 752  1 else { throw new UnsupportedConversionException(); }
 753    }
 754   
 755  8 private Expression unbox(Expression exp, String methodName) {
 756  8 ObjectMethodCall result = new ObjectMethodCall(exp, methodName, null, exp.getSourceInfo());
 757  8 try {
 758  8 ObjectMethodInvocation inv = lookupMethod(exp, methodName, EMPTY_TYPE_ITERABLE, EMPTY_EXPRESSION_ITERABLE,
 759    NONE_TYPE_OPTION, new TopLevelAccessModule(""));
 760  8 result.setExpression(inv.object());
 761  8 result.setArguments(CollectUtil.makeList(inv.args()));
 762  8 NodeProperties.setMethod(result, inv.method());
 763  8 NodeProperties.setType(result, capture(inv.returnType()));
 764  0 if (NodeProperties.hasValue(exp)) { NodeProperties.setValue(result, NodeProperties.getValue(exp)); }
 765  8 return result;
 766    }
 767  0 catch (TypeSystemException e) { throw new RuntimeException("Unboxing method inaccessible", e); }
 768    }
 769   
 770    /**
 771    * Convert the expression to a reference. The result is guaranteed to have a reference type as its
 772    * TYPE property (according to {@link #isReference}).
 773    *
 774    * @param e A typed expression
 775    * @return A typed expression equivalent to {@code e} that has a reference type
 776    * @throws UnsupportedConversionException If the expression cannot be converted to a reference
 777    */
 778  190 public Expression makeReference(final Expression e) throws UnsupportedConversionException {
 779  190 Type t = NodeProperties.getType(e);
 780  172 if (isReference(t)) { return e; }
 781  0 else if (_opt.prohibitBoxing()) { throw new UnsupportedConversionException(); }
 782    else {
 783  18 Expression result = t.apply(new TypeAbstractVisitor<Expression>() {
 784  0 public Expression defaultCase(Type t) { return null; }
 785  2 @Override public Expression forBooleanType(BooleanType t) { return box(e, BOOLEAN_CLASS); }
 786  2 @Override public Expression forCharType(CharType t) { return box(e, CHARACTER_CLASS); }
 787  2 @Override public Expression forByteType(ByteType t) { return box(e, BYTE_CLASS); }
 788  2 @Override public Expression forShortType(ShortType t) { return box(e, SHORT_CLASS); }
 789  5 @Override public Expression forIntType(IntType t) { return box(e, INTEGER_CLASS); }
 790  2 @Override public Expression forLongType(LongType t) { return box(e, LONG_CLASS); }
 791  1 @Override public Expression forFloatType(FloatType t) { return box(e, FLOAT_CLASS); }
 792  2 @Override public Expression forDoubleType(DoubleType t) { return box(e, DOUBLE_CLASS); }
 793    });
 794  0 if (result == null) { throw new UnsupportedConversionException(); }
 795  18 else { return result; }
 796    }
 797    }
 798   
 799  18 private Expression box(Expression exp, ClassType boxedType) {
 800  18 ReferenceTypeName boxedTypeName = new ReferenceTypeName("java", "lang", boxedType.ofClass().declaredName());
 801  18 NodeProperties.setType(boxedTypeName, boxedType);
 802  18 List<Expression> arguments = Collections.singletonList(exp);
 803  18 if (JavaVersion.CURRENT.supports(JavaVersion.JAVA_5)) {
 804  18 StaticMethodCall m = new StaticMethodCall(boxedTypeName, "valueOf", arguments, exp.getSourceInfo());
 805  18 try {
 806  18 MethodInvocation inv = lookupStaticMethod(boxedType, "valueOf", EMPTY_TYPE_ITERABLE, arguments,
 807    NONE_TYPE_OPTION, new TopLevelAccessModule(""));
 808  18 m.setArguments(CollectUtil.makeList(inv.args()));
 809  18 NodeProperties.setMethod(m, inv.method());
 810  18 NodeProperties.setType(m, capture(inv.returnType()));
 811  9 if (NodeProperties.hasValue(exp)) { NodeProperties.setValue(m, NodeProperties.getValue(exp)); }
 812  18 return m;
 813    }
 814  0 catch (TypeSystemException e) { throw new RuntimeException("Boxing method inaccessible", e); }
 815    }
 816    else {
 817  0 SimpleAllocation k = new SimpleAllocation(boxedTypeName, arguments, exp.getSourceInfo());
 818  0 try {
 819  0 ConstructorInvocation inv = lookupConstructor(boxedType, EMPTY_TYPE_ITERABLE, arguments, NONE_TYPE_OPTION,
 820    new TopLevelAccessModule(""));
 821  0 k.setArguments(CollectUtil.makeList(inv.args()));
 822  0 NodeProperties.setConstructor(k, inv.constructor());
 823  0 NodeProperties.setType(k, boxedType);
 824  0 if (NodeProperties.hasValue(exp)) { NodeProperties.setValue(k, NodeProperties.getValue(exp)); }
 825  0 return k;
 826    }
 827  0 catch (TypeSystemException e) { throw new RuntimeException("Boxing constructor inaccessible", e); }
 828    }
 829    }
 830   
 831    /**
 832    * Perform unary numeric promotion on an expression.
 833    *
 834    * @param e A typed expression with a primitive type
 835    * @return A typed expression equivalent to {@code e} with the promoted type
 836    * @throws UnsupportedConversionException If the expression cannot be used for numeric promotion
 837    */
 838  112 public Expression unaryPromote(final Expression e) throws UnsupportedConversionException {
 839    // Note: Variables with primitive bounds are not supported
 840  112 Expression result = NodeProperties.getType(e).apply(new TypeAbstractVisitor<Expression>() {
 841  0 public Expression defaultCase(Type t) { return null; }
 842  112 @Override public Expression forNumericType(NumericType t) { return e; }
 843  0 @Override public Expression forCharType(CharType t) { return makeCast(INT, e); }
 844  0 @Override public Expression forByteType(ByteType t) { return makeCast(INT, e); }
 845  0 @Override public Expression forShortType(ShortType t) { return makeCast(INT, e); }
 846    });
 847  0 if (result == null) { throw new UnsupportedConversionException(); }
 848  112 else { return result; }
 849    }
 850   
 851    /**
 852    * Perform binary numeric promotion on a pair of expressions. The resulting pair of expressions
 853    * are guaranteed to have the same type.
 854    *
 855    * @param e1 A typed expression with a primitive type
 856    * @param e2 A typed expression with a primitive type
 857    * @return Two typed expressions equivalent to {@code e1} and {@code e2} with the promoted type
 858    * @throws UnsupportedConversionException If either expression cannot be used for numeric promotion
 859    */
 860  262 public Pair<Expression, Expression> binaryPromote(final Expression e1, final Expression e2)
 861    throws UnsupportedConversionException {
 862    // Note: Variables with primitive bounds are not fully supported
 863  262 final Type t1 = NodeProperties.getType(e1);
 864  262 final Type t2 = NodeProperties.getType(e2);
 865  262 final Type t1Promoted = t1.apply(new TypeAbstractVisitor<Type>() {
 866  0 @Override public Type defaultCase(Type t) { return null; }
 867  237 @Override public Type forNumericType(NumericType t) { return INT; }
 868  22 @Override public Type forFloatingPointType(FloatingPointType t) { return t; }
 869  3 @Override public Type forLongType(LongType t) { return t; }
 870    });
 871  0 if (t1Promoted == null) { throw new UnsupportedConversionException(); }
 872  262 final Type promoted = t2.apply(new TypeAbstractVisitor<Type>() {
 873  0 @Override public Type defaultCase(Type t) { return null; }
 874  238 @Override public Type forNumericType(NumericType t) { return t1Promoted; }
 875  14 @Override public Type forDoubleType(DoubleType t) { return t; }
 876  8 @Override public Type forFloatType(FloatType t) {
 877  8 return (t1Promoted instanceof DoubleType) ? t1Promoted : t;
 878    }
 879  2 @Override public Type forLongType(LongType t) {
 880  2 return (t1Promoted instanceof FloatingPointType) ? t1Promoted : t;
 881    }
 882    });
 883  0 if (promoted == null) { throw new UnsupportedConversionException(); }
 884   
 885  262 return Pair.make(t1.equals(promoted) ? e1 : makeCast(promoted, e1),
 886  262 t2.equals(promoted) ? e2 : makeCast(promoted, e2));
 887    }
 888   
 889    /**
 890    * Perform a join (as defined for the ? : operator) on a pair of expressions. The resulting pair
 891    * of expressions are guaranteed to have the same type. That type may contain non-captured wildcards.
 892    *
 893    * @param e1 A typed expression
 894    * @param e2 A typed expression
 895    * @return Two typed expressions equivalent to {@code e1} and {@code e2} with the joined type
 896    * @throws UnsupportedConversionException If the two types are incompatible.
 897    */
 898  0 public Pair<Expression, Expression> mergeConditional(final Expression e1, final Expression e2)
 899    throws UnsupportedConversionException {
 900  0 return NodeProperties.getType(e1).apply(new TypeAbstractVisitor<Pair<Expression, Expression>>() {
 901  0 public Pair<Expression, Expression> defaultCase(Type t1) {
 902  0 if (isNumericReference(t1)) { return checkForNumericE2(); }
 903  0 else if (isBooleanReference(t1) && NodeProperties.getType(e2) instanceof BooleanType) {
 904  0 try { return Pair.make(makePrimitive(e1), e2); }
 905  0 catch (UnsupportedConversionException e) { throw new RuntimeException("isBooleanReference() lied"); }
 906    }
 907  0 else { return joinReferences(); }
 908    }
 909   
 910  0 @Override public Pair<Expression, Expression> forBooleanType(BooleanType t1) {
 911  0 Type t2 = NodeProperties.getType(e2);
 912  0 if (t2 instanceof BooleanType) { return Pair.make(e1, e2); }
 913  0 else if (isBooleanReference(t2)) {
 914  0 try { return Pair.make(e1, makePrimitive(e2)); }
 915  0 catch (UnsupportedConversionException e) { throw new RuntimeException("isBooleanReference() lied"); }
 916    }
 917  0 else { return joinReferences(); }
 918    }
 919   
 920  0 @Override public Pair<Expression, Expression> forNumericType(NumericType t1) { return checkForNumericE2(); }
 921   
 922  0 private boolean isNumericReference(Type t) {
 923  0 return !_opt.prohibitBoxing() && !isSubtype(t, NULL) &&
 924    (isSubtype(t, CHARACTER_CLASS) ||
 925    isSubtype(t, BYTE_CLASS) ||
 926    isSubtype(t, SHORT_CLASS) ||
 927    isSubtype(t, INTEGER_CLASS) ||
 928    isSubtype(t, LONG_CLASS) ||
 929    isSubtype(t, FLOAT_CLASS) ||
 930    isSubtype(t, DOUBLE_CLASS));
 931    }
 932   
 933  0 private boolean isBooleanReference(Type t) {
 934  0 return !_opt.prohibitBoxing() && isSubtype(t, BOOLEAN_CLASS) && !isSubtype(t, NULL);
 935    }
 936   
 937  0 private Pair<Expression, Expression> checkForNumericE2() {
 938  0 return NodeProperties.getType(e2).apply(new TypeAbstractVisitor<Pair<Expression, Expression>>() {
 939  0 public Pair<Expression, Expression> defaultCase(Type t2) {
 940  0 if (isNumericReference(t2)) { return joinNumbers(); }
 941  0 else { return joinReferences(); }
 942    }
 943  0 @Override public Pair<Expression, Expression> forNumericType(NumericType t2) { return joinNumbers(); }
 944    });
 945    }
 946   
 947  0 private Pair<Expression, Expression> joinNumbers() {
 948  0 try {
 949  0 Expression unboxed1 = makePrimitive(e1);
 950  0 Expression unboxed2 = makePrimitive(e2);
 951  0 Type numT1 = NodeProperties.getType(unboxed1);
 952  0 Type numT2 = NodeProperties.getType(unboxed2);
 953  0 Type joined = null;
 954  0 if (NodeProperties.hasValue(unboxed1) && numT1 instanceof IntType) {
 955  0 joined = inRange(NodeProperties.getValue(unboxed1), numT2) ? numT2 : null;
 956    }
 957  0 if (joined == null && NodeProperties.hasValue(unboxed2) && numT2 instanceof IntType) {
 958  0 joined = inRange(NodeProperties.getValue(unboxed2), numT1) ? numT1 : null;
 959    }
 960  0 if (joined == null) { joined = join(numT1, numT2); }
 961  0 Expression result1 = isEqual(numT1, joined) ? unboxed1 : makeCast(joined, unboxed1);
 962  0 Expression result2 = isEqual(numT2, joined) ? unboxed2 : makeCast(joined, unboxed2);
 963  0 return Pair.make(result1, result2);
 964    }
 965  0 catch (UnsupportedConversionException e) { throw new IllegalArgumentException(e); }
 966    }
 967   
 968  0 private Pair<Expression, Expression> joinReferences() {
 969  0 try {
 970  0 Expression boxed1 = makeReference(e1);
 971  0 Expression boxed2 = makeReference(e2);
 972  0 Type refT1 = NodeProperties.getType(boxed1);
 973  0 Type refT2 = NodeProperties.getType(boxed2);
 974  0 Type joined = join(refT1, refT2);
 975  0 Expression result1 = isEqual(refT1, joined) ? boxed1 : makeCast(joined, boxed1);
 976  0 Expression result2 = isEqual(refT2, joined) ? boxed2 : makeCast(joined, boxed2);
 977  0 return Pair.make(result1, result2);
 978    }
 979  0 catch (UnsupportedConversionException e) { throw new IllegalArgumentException(); }
 980    }
 981   
 982    });
 983    }
 984   
 985    /**
 986    * Perform a cast on the given expression. Any necessary conversions are performed. One of
 987    * {@code CHECKED_TYPE}, {@code CONVERTED_TYPE}, or {@code ASSERTED_TYPE} is set on the result.
 988    *
 989    * @return An expression equivalent to {@code e}, wrapped in any necessary conversions
 990    * @throws UnsupportedConversionException If the cast is to an incompatible type.
 991    */
 992  14 public Expression cast(final Type target, final Expression e) throws UnsupportedConversionException {
 993  14 Expression result = target.apply(new TypeAbstractVisitor<Expression>() {
 994   
 995  14 @Override public Expression forPrimitiveType(PrimitiveType target) {
 996  14 try {
 997  14 Expression result = makePrimitive(e);
 998  14 Type source = NodeProperties.getType(result);
 999   
 1000    // type check valid conversions, see ExpressionEvaluator.convert
 1001  14 if (target.equals(BOOLEAN)) {
 1002  0 if (!source.equals(BOOLEAN)) { throw new UnsupportedConversionException(); }
 1003    }
 1004  14 else if (target.equals(CHAR) ||
 1005    target.equals(BYTE) ||
 1006    target.equals(SHORT) ||
 1007    target.equals(INT) ||
 1008    target.equals(LONG) ||
 1009    target.equals(FLOAT) ||
 1010    target.equals(DOUBLE)) {
 1011  14 if ((!source.equals(CHAR)) &&
 1012    (!source.equals(BYTE)) &&
 1013    (!source.equals(DOUBLE)) &&
 1014    (!source.equals(FLOAT)) &&
 1015    (!source.equals(INT)) &&
 1016    (!source.equals(LONG)) &&
 1017  0 (!source.equals(SHORT))) { throw new UnsupportedConversionException(); }
 1018    }
 1019  0 else { throw new IllegalArgumentException(); }
 1020    // end type check valid conversions
 1021   
 1022  14 if (!isEqual(target, source)) { NodeProperties.setConvertedType(result, erasedClass(target)); }
 1023  14 return result;
 1024    }
 1025  0 catch (UnsupportedConversionException e) { return null; }
 1026    }
 1027   
 1028  0 @Override public Expression defaultCase(Type target) {
 1029  0 try {
 1030  0 Expression result = makeReference(e);
 1031  0 Type source = NodeProperties.getType(result);
 1032  0 if (isSubtype(source, target)) {
 1033  0 NodeProperties.setAssertedType(result, erasedClass(target));
 1034    }
 1035    else {
 1036  0 if (!isDisjoint(source, target) && (!_opt.prohibitUncheckedCasts() || validCheckedCast(target, source))) {
 1037  0 NodeProperties.setCheckedType(result, erasedClass(target));
 1038    }
 1039  0 else { throw new UnsupportedConversionException(); }
 1040    }
 1041  0 return result;
 1042    }
 1043  0 catch (UnsupportedConversionException e) { return null; }
 1044    }
 1045    });
 1046  0 if (result == null) { throw new UnsupportedConversionException(); }
 1047  14 else { return result; }
 1048    }
 1049   
 1050    /**
 1051    * Whether a reference down-cast is valid and guaranteed safe. May assume that
 1052    * source is not a subtype of target and that the two are not disjoint. See JLS 5.5.
 1053    */
 1054  0 private boolean validCheckedCast(Type target, final Type source) {
 1055  0 return target.apply(new TypeAbstractVisitor<Boolean>() {
 1056  0 @Override public Boolean defaultCase(Type target) { return isReifiable(target); }
 1057  0 @Override public Boolean forParameterizedClassType(ParameterizedClassType target) {
 1058  0 if (isReifiable(target)) { return true; }
 1059  0 else if (isSubtype(target, source)) {
 1060    // Verify that, given a value of type source & erase(target), it must have type target.
 1061    // Must show, where target=Target<T1..Tn>, forall X1..Xn, Target<X1..Xn> <: source implies Xi=Ti.
 1062  0 ParameterizedClassType wildCapt = capture(parameterize(new RawClassType(target.ofClass())));
 1063  0 Iterable<VariableType> unboundArgs =
 1064    IterUtil.filterInstances(IterUtil.relax(wildCapt.typeArguments()), VariableType.class);
 1065  0 Iterable<Type> boundArgs = inferTypeArguments(unboundArgs, EMPTY_TYPE_ITERABLE, wildCapt,
 1066    EMPTY_TYPE_ITERABLE, Option.some(source));
 1067  0 return boundArgs != null && IterUtil.and(boundArgs, target.typeArguments(), new Predicate2<Type, Type>() {
 1068  0 public boolean contains(Type inferred, Type orig) { return isEqual(inferred, orig); }
 1069    });
 1070    }
 1071  0 else { return false; }
 1072    }
 1073  0 @Override public Boolean forArrayType(ArrayType target) {
 1074  0 if (isArray(source)) { return validCheckedCast(target.ofType(), arrayElementType(source)); }
 1075  0 else { return defaultCase(target); }
 1076    }
 1077    });
 1078    }
 1079   
 1080    /**
 1081    * Prepare the given expression for assignment, wrapping it in any necessary conversions.
 1082    *
 1083    * @return An expression equivalent to {@code e}, wrapped in any necessary conversions
 1084    * @throws UnsupportedConversionException If assignment to the given type is incorrect.
 1085    */
 1086  1408 public Expression assign(final Type target, final Expression exp) throws UnsupportedConversionException {
 1087  1408 try {
 1088  1408 return target.apply(new TypeAbstractVisitor<Expression>() {
 1089   
 1090  947 public Expression defaultCase(final Type target) {
 1091  947 return NodeProperties.getType(exp).apply(new TypeAbstractVisitor<Expression>() {
 1092  939 public Expression defaultCase(Type t) {
 1093    // TODO: Allow unchecked conversions from raw types (matching the spec is not trivial)
 1094  735 if (isSubtype(t, target)) { return exp; }
 1095  204 else { throw new WrappedException(new UnsupportedConversionException()); }
 1096    }
 1097   
 1098  8 @Override public Expression forPrimitiveType(PrimitiveType t) {
 1099  8 try {
 1100  8 Expression boxed = makeReference(exp);
 1101  8 if (isSubtype(NodeProperties.getType(boxed), target)) { return exp; }
 1102  0 else { throw new UnsupportedConversionException(); }
 1103    }
 1104  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1105    }
 1106   
 1107  1 @Override public Expression forCharType(CharType t) {
 1108  1 try {
 1109  1 if (NodeProperties.hasValue(exp)) {
 1110  1 if (isEqual(target, BYTE_CLASS) && inRange(NodeProperties.getValue(exp), BYTE)) {
 1111  0 return makeReference(makeCast(BYTE, exp));
 1112    }
 1113  1 else if (isEqual(target, SHORT_CLASS) && inRange(NodeProperties.getValue(exp), SHORT)) {
 1114  0 return makeReference(makeCast(SHORT, exp));
 1115    }
 1116    }
 1117  1 return forPrimitiveType(t);
 1118    }
 1119  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1120    }
 1121   
 1122  1 @Override public Expression forByteType(ByteType t) {
 1123  1 try {
 1124  1 if (NodeProperties.hasValue(exp)) {
 1125  0 if (isEqual(target, CHARACTER_CLASS) && inRange(NodeProperties.getValue(exp), CHAR)) {
 1126  0 return makeReference(makeCast(CHAR, exp));
 1127    }
 1128    }
 1129  1 return forPrimitiveType(t);
 1130    }
 1131  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1132    }
 1133   
 1134  1 @Override public Expression forShortType(ShortType t) {
 1135  1 try {
 1136  1 if (NodeProperties.hasValue(exp)) {
 1137  0 if (isEqual(target, BYTE_CLASS) && inRange(NodeProperties.getValue(exp), BYTE)) {
 1138  0 return makeReference(makeCast(BYTE, exp));
 1139    }
 1140  0 else if (isEqual(target, CHARACTER_CLASS) && inRange(NodeProperties.getValue(exp), CHAR)) {
 1141  0 return makeReference(makeCast(CHAR, exp));
 1142    }
 1143    }
 1144  1 return forPrimitiveType(t);
 1145    }
 1146  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1147    }
 1148   
 1149  1 @Override public Expression forIntType(IntType t) {
 1150  1 try {
 1151  1 if (NodeProperties.hasValue(exp)) {
 1152  1 if (isEqual(target, BYTE_CLASS) && inRange(NodeProperties.getValue(exp), BYTE)) {
 1153  0 return makeReference(makeCast(BYTE, exp));
 1154    }
 1155  1 else if (isEqual(target, SHORT_CLASS) && inRange(NodeProperties.getValue(exp), SHORT)) {
 1156  0 return makeReference(makeCast(SHORT, exp));
 1157    }
 1158  1 else if (isEqual(target, CHARACTER_CLASS) && inRange(NodeProperties.getValue(exp), CHAR)) {
 1159  0 return makeReference(makeCast(CHAR, exp));
 1160    }
 1161    }
 1162  1 return forPrimitiveType(t);
 1163    }
 1164  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1165    }
 1166    });
 1167    }
 1168   
 1169  441 @Override public Expression forPrimitiveType(PrimitiveType target) {
 1170  441 try {
 1171  441 Expression unboxed = makePrimitive(exp);
 1172  441 Type t = NodeProperties.getType(unboxed);
 1173  437 if (isEqual(t, target)) { return unboxed; }
 1174  4 else if (isSubtype(t, target)) { return makeCast(target, unboxed); }
 1175  0 else { throw new UnsupportedConversionException(); }
 1176    }
 1177  0 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1178    }
 1179   
 1180  8 @Override public Expression forCharType(CharType target) { return handleSmallPrimitive(target); }
 1181  6 @Override public Expression forByteType(ByteType target) { return handleSmallPrimitive(target); }
 1182  6 @Override public Expression forShortType(ShortType target) { return handleSmallPrimitive(target); }
 1183   
 1184  20 private Expression handleSmallPrimitive(PrimitiveType target) {
 1185  20 try {
 1186  20 Expression unboxed = makePrimitive(exp);
 1187  20 Type t = NodeProperties.getType(unboxed);
 1188  20 if (NodeProperties.hasValue(unboxed) && t instanceof IntegralType && !(t instanceof LongType) &&
 1189  6 inRange(NodeProperties.getValue(unboxed), target)) { return makeCast(target, unboxed); }
 1190  11 else if (isEqual(t, target)) { return unboxed; }
 1191  0 else if (isSubtype(t, target)) { return makeCast(target, unboxed); }
 1192  3 else { throw new UnsupportedConversionException(); }
 1193    }
 1194  3 catch (UnsupportedConversionException e) { throw new WrappedException(e); }
 1195    }
 1196   
 1197    });
 1198    }
 1199    catch (WrappedException e) {
 1200  207 if (e.getCause() instanceof UnsupportedConversionException) {
 1201  207 throw (UnsupportedConversionException) e.getCause();
 1202    }
 1203  0 else { throw e; }
 1204    }
 1205    }
 1206   
 1207   
 1208    /**
 1209    * Wrap {@code e} in a cast to type {@code target}. The cast is assumed to be legal. The
 1210    * result will be a {@link CastExpression} with a {@code null} value for its {@code TypeName},
 1211    * and with the {@code TYPE} property set. {@code CONVERTED_TYPE} and {@code CHECKED_TYPE} may
 1212    * also be set on {@code e}, as necessary.
 1213    */
 1214  204 private Expression makeCast(Type target, Expression e) {
 1215  204 Expression result = new CastExpression(null, e, e.getSourceInfo());
 1216  204 if (isPrimitive(target)) {
 1217  27 if (!isEqual(target, NodeProperties.getType(e))) {
 1218  21 NodeProperties.setConvertedType(result, erasedClass(target));
 1219  21 if (NodeProperties.hasValue(e)) {
 1220  1 Object orig = NodeProperties.getValue(e);
 1221  1 Class<?> t = NodeProperties.getConvertedType(result).value();
 1222  1 NodeProperties.setValue(result, ExpressionEvaluator.convert(orig, t));
 1223    }
 1224    }
 1225    else {
 1226  6 if (NodeProperties.hasValue(e)) { NodeProperties.setValue(result, NodeProperties.getValue(e)); }
 1227    }
 1228    }
 1229    else {
 1230    // TODO: Add a checked type property, if necessary
 1231    }
 1232   
 1233  204 NodeProperties.setType(result, target);
 1234  204 return result;
 1235    }
 1236   
 1237  20 private Expression makeArray(ArrayType arrayType, Iterable<? extends Expression> elements) {
 1238  20 Thunk<Class<?>> erasedType = erasedClass(arrayType);
 1239  20 TypeName tn = TypeUtil.makeEmptyTypeName();
 1240    // TODO: Is it necessary to create a type name that corresponds to the element type (this is not
 1241    // possible in general, but possible in situations in which this method is called), or
 1242    // is an "empty" type name sufficient?
 1243  20 NodeProperties.setType(tn, arrayType.ofType());
 1244  20 ArrayInitializer init = new ArrayInitializer(CollectUtil.makeList(elements));
 1245  20 NodeProperties.setType(init, arrayType);
 1246  20 NodeProperties.setErasedType(init, erasedType);
 1247  20 Expression result = new ArrayAllocation(tn, new ArrayAllocation.TypeDescriptor(new ArrayList<Expression>(0),
 1248    1, init, SourceInfo.NONE));
 1249  20 NodeProperties.setType(result, arrayType);
 1250  20 NodeProperties.setErasedType(result, erasedType);
 1251  20 return result;
 1252    }
 1253   
 1254    /**
 1255    * True iff the given value (from a constant) is in range of the given type (regardless of whether
 1256    * an assignment to type {@code t} would require a narrowing conversion)
 1257    */
 1258  6 private boolean inRange(final Object value, Type t) {
 1259  0 if (isReference(t)) { return value == null; }
 1260  6 else return t.apply(new TypeAbstractVisitor<Boolean>() {
 1261  0 public Boolean defaultCase(Type t) { return false; }
 1262  0 @Override public Boolean forBooleanType(BooleanType t) { return value instanceof Boolean; }
 1263  6 @Override public Boolean forCharType(CharType t) { return checkNumber(Character.MIN_VALUE, Character.MAX_VALUE); }
 1264  0 @Override public Boolean forByteType(ByteType t) { return checkNumber(Byte.MIN_VALUE, Byte.MAX_VALUE); }
 1265  0 @Override public Boolean forShortType(ShortType t) { return checkNumber(Short.MIN_VALUE, Short.MAX_VALUE); }
 1266  0 @Override public Boolean forIntType(IntType t) { return checkNumber(Integer.MIN_VALUE, Integer.MAX_VALUE); }
 1267  0 @Override public Boolean forLongType(LongType t) { return checkNumber(Long.MIN_VALUE, Long.MAX_VALUE); }
 1268  6 private Boolean checkNumber(long lowerBound, long upperBound) {
 1269  6 if (value instanceof Number && !(value instanceof Float) && !(value instanceof Double)) {
 1270  0 long val = ((Number) value).longValue();
 1271  0 return lowerBound <= val && val <= upperBound;
 1272    }
 1273  6 else if (value instanceof Character) {
 1274  6 long val = ((Character) value).charValue();
 1275  6 return lowerBound <= val && val <= upperBound;
 1276    }
 1277  0 else { return false; }
 1278    }
 1279    });
 1280    }
 1281   
 1282    /** Get a class type's immediate supertype. The result may be null. */
 1283  37652 protected Type immediateSupertype(ClassType t) {
 1284  14558 if (t.equals(OBJECT)) { return null; }
 1285    else {
 1286  23094 final Iterable<Type> declaredSupers = t.ofClass().declaredSupertypes();
 1287  13488 if (IterUtil.isEmpty(declaredSupers)) { return OBJECT; }
 1288    else {
 1289  9606 Iterable<? extends Type> instantiatedSupers = t.apply(new TypeAbstractVisitor<Iterable<? extends Type>>() {
 1290  2870 @Override public Iterable<? extends Type> defaultCase(Type t) { return declaredSupers; }
 1291  4238 @Override public Iterable<? extends Type> forRawClassType(RawClassType t) {
 1292  4238 return IterUtil.mapSnapshot(declaredSupers, ERASE);
 1293    }
 1294  2498 @Override public Iterable<? extends Type> forParameterizedClassType(ParameterizedClassType t) {
 1295  2498 ParameterizedClassType tCap = capture(t);
 1296  2498 DJClass c = tCap.ofClass();
 1297  2498 return substitute(c.declaredSupertypes(), SymbolUtil.allTypeParameters(c), tCap.typeArguments());
 1298    }
 1299    });
 1300  3256 if (IterUtil.sizeOf(instantiatedSupers, 2) > 1) { return new IntersectionType(instantiatedSupers); }
 1301  6350 else { return IterUtil.first(instantiatedSupers); }
 1302    }
 1303    }
 1304    }
 1305   
 1306    /**
 1307    * Lookup the constructor corresponding the the given invocation.
 1308    * @param t The type of the object to be constructed.
 1309    * @param typeArgs The type arguments for the constructor's type parameters.
 1310    * @param args A list of typed expressions corresponding to the constructor's parameters.
 1311    * @param expected The type expected in the invocation's calling context, if any.
 1312    * @return A {@link TypeSystem.ConstructorInvocation} object representing the matched constructor.
 1313    * @throws InvalidTypeArgumentException If the type arguments are invalid (for example, a primitive type).
 1314    * @throws UnmatchedLookupException If 0 or more than 1 constructor matches the given arguments and type
 1315    * arguments.
 1316    */
 1317    // TODO: Must produce a reasonable value when looking up a constructor in an interface (for anonymous classes)
 1318  552 public ConstructorInvocation lookupConstructor(final Type t, final Iterable<? extends Type> typeArgs,
 1319    final Iterable<? extends Expression> args,
 1320    final Option<Type> expected, final Access.Module accessModule)
 1321    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1322  552 debug.logStart(new String[]{"t","typeArgs","arg types","expected"},
 1323  552 wrap(t), wrap(typeArgs), wrap(IterUtil.map(args, NodeProperties.NODE_TYPE)), wrap(expected)); try {
 1324   
 1325  552 Iterable<DJConstructor> constructors =
 1326    t.apply(new TypeAbstractVisitor<Iterable<DJConstructor>>() {
 1327  0 @Override public Iterable<DJConstructor> defaultCase(Type t) { return IterUtil.empty(); }
 1328  339 @Override public Iterable<DJConstructor> forSimpleClassType(SimpleClassType t) {
 1329  339 return t.ofClass().declaredConstructors();
 1330    }
 1331  0 @Override public Iterable<DJConstructor> forRawClassType(RawClassType t) {
 1332  0 return IterUtil.mapSnapshot(t.ofClass().declaredConstructors(), new Lambda<DJConstructor, DJConstructor>() {
 1333  0 public DJConstructor value(DJConstructor k) {
 1334    // TODO: raw member access warnings
 1335  0 return new ErasedConstructor(k);
 1336    }
 1337    });
 1338    }
 1339  213 @Override public Iterable<DJConstructor> forParameterizedClassType(ParameterizedClassType t) {
 1340  213 final Iterable<VariableType> classTParams = SymbolUtil.allTypeParameters(t.ofClass());
 1341  213 final Iterable<? extends Type> classTArgs = capture(t).typeArguments();
 1342  213 return IterUtil.mapSnapshot(t.ofClass().declaredConstructors(), new Lambda<DJConstructor, DJConstructor>() {
 1343  220 public DJConstructor value(DJConstructor k) {
 1344  220 return new InstantiatedConstructor(k, classTParams, classTArgs);
 1345    }
 1346    });
 1347    }
 1348    });
 1349   
 1350  552 Iterable<DJConstructor> accessible = IterUtil.filter(constructors, new Predicate<DJConstructor>() {
 1351  1216 public boolean contains(DJConstructor k) { return accessible(k, accessModule); }
 1352    });
 1353  552 Iterable<FunctionInvocationCandidate<DJConstructor>> cs = bestInvocations(accessible, typeArgs, args, expected);
 1354    // TODO: provide more error-message information
 1355  552 int matches = IterUtil.sizeOf(cs);
 1356  1 if (matches == 0) { throw new UnmatchedFunctionLookupException(constructors); }
 1357  551 else if (matches > 1) {
 1358  0 Iterable<DJConstructor> ks = IterUtil.map(cs, new Lambda<FunctionInvocationCandidate<DJConstructor>,
 1359    DJConstructor>() {
 1360  0 public DJConstructor value(FunctionInvocationCandidate<DJConstructor> c) { return c.function(); }
 1361    });
 1362  0 throw new AmbiguousFunctionLookupException(ks);
 1363    }
 1364    else {
 1365  551 FunctionInvocationCandidate<DJConstructor> c = IterUtil.first(cs);
 1366  551 DJConstructor k = c.function();
 1367  551 SubstitutionMap sigma = c.substitution();
 1368  551 return new ConstructorInvocation(k, c.typeArguments(), c.arguments(), substitute(k.thrownTypes(), sigma));
 1369    }
 1370   
 1371  552 } finally { debug.logEnd(); }
 1372    }
 1373   
 1374  0 public boolean containsMethod(Type t, String name, Access.Module accessModule) {
 1375  0 return new MethodFinder(name, accessModule, false).hasMatch(t);
 1376    }
 1377  0 public boolean containsStaticMethod(Type t, String name, Access.Module accessModule) {
 1378  0 return new MethodFinder(name, accessModule, true).hasMatch(t);
 1379    }
 1380   
 1381  107 public ObjectMethodInvocation lookupMethod(Expression object, String name,
 1382    Iterable<? extends Type> typeArgs,
 1383    Iterable<? extends Expression> args,
 1384    Option<Type> expected, Access.Module accessModule)
 1385    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1386  107 Type t = NodeProperties.getType(object);
 1387  107 FunctionInvocationCandidate<DJMethod> result =
 1388    new MethodFinder(name, accessModule, false).findSingleMethod(t, typeArgs, args, expected);
 1389  97 DJMethod m = result.function();
 1390  97 SubstitutionMap sigma = result.substitution();
 1391    // TODO: Is there any reason to invoke makeCast on the receiver?
 1392  97 return new ObjectMethodInvocation(m, substitute(m.returnType(), sigma), object, result.typeArguments(),
 1393    result.arguments(), substitute(m.thrownTypes(), sigma));
 1394    }
 1395   
 1396  179 public StaticMethodInvocation lookupStaticMethod(Type t, String name,
 1397    Iterable<? extends Type> typeArgs,
 1398    Iterable<? extends Expression> args,
 1399    Option<Type> expected, Access.Module accessModule)
 1400    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1401  179 FunctionInvocationCandidate<DJMethod> result =
 1402    new MethodFinder(name, accessModule, true).findSingleMethod(t, typeArgs, args, expected);
 1403  173 DJMethod m = result.function();
 1404  173 SubstitutionMap sigma = result.substitution();
 1405  173 return new StaticMethodInvocation(m, substitute(m.returnType(), sigma), result.typeArguments(),
 1406    result.arguments(), substitute(m.thrownTypes(), sigma));
 1407    }
 1408   
 1409  260 public boolean containsField(Type t, String name, Access.Module accessModule) {
 1410  260 return containsField(t, name, accessModule, false);
 1411    }
 1412  0 public boolean containsStaticField(Type t, String name, Access.Module accessModule) {
 1413  0 return containsField(t, name, accessModule, true);
 1414    }
 1415  260 private boolean containsField(Type t, String name, Access.Module accessModule, boolean onlyStatic) {
 1416  260 FieldFinder<FieldReference> finder = new FieldFinder<FieldReference>(name, accessModule, onlyStatic) {
 1417  254 protected FieldReference makeFieldReference(Type t, DJField f) {
 1418  254 return new FieldReference(f, BOTTOM) {}; // anonymous stub just used for inheritance checking
 1419    }
 1420    };
 1421  260 return finder.hasMatch(t);
 1422    }
 1423   
 1424  177 public ObjectFieldReference lookupField(final Expression object, String name, Access.Module accessModule)
 1425    throws UnmatchedLookupException {
 1426  177 FieldFinder<ObjectFieldReference> finder = new FieldFinder<ObjectFieldReference>(name, accessModule, false) {
 1427  177 public ObjectFieldReference makeFieldReference(Type t, DJField f) {
 1428  177 return new ObjectFieldReference(f, fieldType(f, t), makeCast(t, object));
 1429    }
 1430    };
 1431  177 return finder.findSingleField(NodeProperties.getType(object));
 1432    }
 1433   
 1434  1 public StaticFieldReference lookupStaticField(Type t, String name, Access.Module accessModule)
 1435    throws UnmatchedLookupException {
 1436  1 FieldFinder<StaticFieldReference> finder = new FieldFinder<StaticFieldReference>(name, accessModule, true) {
 1437  1 public StaticFieldReference makeFieldReference(Type t, DJField f) {
 1438  1 return new StaticFieldReference(f, fieldType(f, t));
 1439    }
 1440    };
 1441  1 return finder.findSingleField(t);
 1442    }
 1443   
 1444  178 private Type fieldType(final DJField f, Type declaringType) {
 1445  178 Type dynamicContext;
 1446  178 if (f.isStatic()) {
 1447  1 if (declaringType instanceof ClassType) {
 1448  1 dynamicContext = SymbolUtil.dynamicOuterClassType((ClassType) declaringType);
 1449    }
 1450  0 else { dynamicContext = null; }
 1451    }
 1452  177 else { dynamicContext = declaringType; }
 1453  1 if (dynamicContext == null) { return f.type(); }
 1454    else {
 1455  177 return dynamicContext.apply(new TypeAbstractVisitor<Type>() {
 1456  108 @Override public Type defaultCase(Type dynamicContext) { return f.type(); }
 1457  0 @Override public Type forRawClassType(RawClassType dynamicContext) {
 1458    // TODO: raw member access warnings
 1459  0 return erase(f.type());
 1460    }
 1461  69 @Override public Type forParameterizedClassType(ParameterizedClassType dynamicContext) {
 1462  69 ParameterizedClassType dynamicContextCap = capture(dynamicContext);
 1463  69 Iterable<VariableType> tparams = SymbolUtil.allTypeParameters(dynamicContextCap.ofClass());
 1464  69 return substitute(f.type(), tparams, dynamicContextCap.typeArguments());
 1465    }
 1466    });
 1467    }
 1468    }
 1469   
 1470  524 public boolean containsClass(Type t, String name, Access.Module accessModule) {
 1471  524 return new ClassFinder(name, EMPTY_TYPE_ITERABLE, accessModule, false).hasMatch(t);
 1472    }
 1473   
 1474  0 public boolean containsStaticClass(Type t, String name, Access.Module accessModule) {
 1475  0 return new ClassFinder(name, EMPTY_TYPE_ITERABLE, accessModule, true).hasMatch(t);
 1476    }
 1477   
 1478  0 public ClassType lookupClass(Expression object, String name, Iterable<? extends Type> typeArgs,
 1479    Access.Module accessModule)
 1480    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1481  0 return new ClassFinder(name, typeArgs, accessModule, false).findSingleClass(NodeProperties.getType(object));
 1482    }
 1483   
 1484  0 public ClassType lookupClass(Type t, String name, Iterable<? extends Type> typeArgs, Access.Module accessModule)
 1485    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1486  0 return new ClassFinder(name, typeArgs, accessModule, false).findSingleClass(t);
 1487    }
 1488   
 1489  0 public ClassType lookupStaticClass(Type t, final String name, final Iterable<? extends Type> typeArgs,
 1490    Access.Module accessModule)
 1491    throws InvalidTypeArgumentException, UnmatchedLookupException {
 1492  0 return new ClassFinder(name, typeArgs, accessModule, true).findSingleClass(t);
 1493    }
 1494   
 1495    /**
 1496    * Determine whether the given symbol should be considered accessible from the given accessing context
 1497    * (for the purposes of lookup).
 1498    */
 1499  1978 private boolean accessible(Access.Limited symbol, Access.Module accessingModule) {
 1500  1978 switch (symbol.accessibility()) {
 1501  322 case PRIVATE:
 1502  322 return (!_opt.enforcePrivateAccess() && !_opt.enforceAllAccess()) ||
 1503    symbol.accessModule().equals(accessingModule);
 1504  0 case PACKAGE:
 1505  0 return !_opt.enforceAllAccess() ||
 1506    symbol.accessModule().packageName().equals(accessingModule.packageName());
 1507  0 case PROTECTED:
 1508    // TODO: implement protected-access checks
 1509  0 return !_opt.enforceAllAccess() || true;
 1510  1656 default:
 1511  1656 return true; // public access is always valid
 1512    }
 1513    }
 1514   
 1515    /**
 1516    * Test whether the given arguments are within the bounds of the corresponding parameters. Assumes
 1517    * that {@code params} and {@code args} have matching arity.
 1518    *
 1519    * @return {@code true} iff the given arguments are within the bounds of the given parameters
 1520    */
 1521  531 protected boolean inBounds(Iterable<? extends VariableType> params, Iterable<? extends Type> args) {
 1522  531 SubstitutionMap sigma = new SubstitutionMap(params, args);
 1523  531 for (Pair<VariableType, Type> pair : IterUtil.zip(params, args)) {
 1524  531 VariableType param = pair.first();
 1525  531 Type arg = pair.second();
 1526  0 if (!isSubtype(substitute(param.symbol().lowerBound(), sigma), arg)) { return false; }
 1527  2 if (!isSubtype(arg, substitute(param.symbol().upperBound(), sigma))) { return false; }
 1528    }
 1529  529 return true;
 1530    }
 1531   
 1532   
 1533    private class StandardTypePrinter implements TypePrinter {
 1534   
 1535    private final Map<VariableType, String> _names = new HashMap<VariableType, String>();
 1536    int _captureVars = 0;
 1537   
 1538  75 public String print(Type t) {
 1539  75 Visitor v = new Visitor();
 1540  75 v.run(t);
 1541  75 v.appendConstraints();
 1542  75 return v.result();
 1543    }
 1544   
 1545  34 public String print(Iterable<? extends Type> ts) {
 1546  34 Visitor v = new Visitor();
 1547  34 v.runOnList(ts, ", ");
 1548  34 v.appendConstraints();
 1549  34 return v.result();
 1550    }
 1551   
 1552  17 public String print(Function f) {
 1553  17 Visitor v = new Visitor();
 1554  17 if (!IterUtil.isEmpty(f.typeParameters())) {
 1555  2 v.append("<");
 1556  2 v.runOnList(f.typeParameters(), ", ");
 1557  2 v.append("> ");
 1558    }
 1559  17 if (!(f instanceof DJConstructor)) {
 1560  16 v.run(f.returnType());
 1561  16 v.append(" ");
 1562    }
 1563  17 v.append(f.declaredName());
 1564  17 v.append("(");
 1565  17 v.runOnList(SymbolUtil.parameterTypes(f), ", ");
 1566  17 v.append(")");
 1567  17 v.appendConstraints();
 1568  17 return v.result();
 1569    }
 1570   
 1571    private class Visitor extends TypeVisitorRunnable1 {
 1572    private final StringBuilder _result = new StringBuilder();
 1573    private final RecursionStack<Type> _stack = new RecursionStack<Type>();
 1574    // variables that have bounds that should be printed in appendConstraints()
 1575    private final List<VariableType> _boundedVars = new ArrayList<VariableType>();
 1576    private final Set<VariableType> _seenVars = new HashSet<VariableType>();
 1577   
 1578  126 public String result() { return _result.toString(); }
 1579   
 1580  71 public void append(String s) { _result.append(s); }
 1581   
 1582  126 public void appendConstraints() {
 1583  126 if (!_boundedVars.isEmpty()) {
 1584  12 _result.append(" [");
 1585    // not using an iterator because the list may grow during iteration
 1586  12 for (int i = 0; i < _boundedVars.size(); i++) {
 1587  0 if (i > 0) { _result.append("; "); }
 1588  12 VariableType v = _boundedVars.get(i);
 1589  12 Type upper = v.symbol().upperBound();
 1590  12 Type lower = v.symbol().lowerBound();
 1591  12 boolean printUpper = !isEqual(upper, OBJECT) /*&& !isEqual(upper, TOP)*/;
 1592  12 boolean printLower = !isEqual(lower, NULL) /*&& !isEqual(lower, BOTTOM)*/;
 1593  12 if (printUpper) {
 1594  9 _result.append(nameForVariable(v));
 1595  9 _result.append(" <: ");
 1596  9 run(upper); // may increase the size of _vars
 1597    }
 1598  12 if (printLower) {
 1599  4 if (printUpper) { _result.append(", "); }
 1600  7 _result.append(nameForVariable(v));
 1601  7 _result.append(" :> ");
 1602  7 run(lower); // may increase the size of _vars
 1603    }
 1604    }
 1605  12 _result.append("]");
 1606    }
 1607    }
 1608   
 1609  38 private String nameForVariable(VariableType t) {
 1610  38 String name = _names.get(t);
 1611  38 if (name == null) {
 1612  11 if (t.symbol().generated()) { _captureVars++; name = "?T" + _captureVars; }
 1613  2 else { name = t.symbol().name(); }
 1614  13 _names.put(t, name);
 1615    }
 1616  38 if (!_seenVars.contains(t)) {
 1617  17 _seenVars.add(t);
 1618    // check to see if bounds need to be printed
 1619  17 Type upper = t.symbol().upperBound();
 1620  17 Type lower = t.symbol().lowerBound();
 1621  17 boolean printUpper = !isEqual(upper, OBJECT) /*&& !isEqual(upper, TOP)*/;
 1622  17 boolean printLower = !isEqual(lower, NULL) /*&& !isEqual(lower, BOTTOM)*/;
 1623  12 if (printUpper || printLower) { _boundedVars.add(t); }
 1624    }
 1625  38 return name;
 1626    }
 1627   
 1628    /**
 1629    * Running is preferred over applying the visitor, as invoking this will put the
 1630    * value being processed on the stack, and avoid unnecessary repetition
 1631    */
 1632  214 @Override public void run(final Type t) {
 1633    // String prefix = ""; for (int i = 0; i < _stack.size(); i++) { prefix += " "; }
 1634    // System.out.println(prefix + "Running on id " + System.identityHashCode(t) + ": " + t);
 1635  214 Runnable recur = new Runnable() { public void run() { t.apply(Visitor.this); } };
 1636  0 Runnable dontRecur = new Runnable() { public void run() { _result.append("..."); } };
 1637    //Threshold of 2 causes the loop to be printed twice
 1638  214 _stack.run(recur, dontRecur, t/*, 2*/);
 1639    }
 1640   
 1641  53 public void runOnList(Iterable<? extends Type> ts, String delim) {
 1642  53 boolean first = true;
 1643  53 for (Type t : ts) {
 1644  14 if (!first) { _result.append(delim); }
 1645  46 first = false;
 1646  46 run(t);
 1647    }
 1648    }
 1649   
 1650  0 public void forBooleanType(BooleanType t) { _result.append("boolean"); }
 1651  1 public void forCharType(CharType t) { _result.append("char"); }
 1652  1 public void forByteType(ByteType t) { _result.append("byte"); }
 1653  1 public void forShortType(ShortType t) { _result.append("short"); }
 1654  24 public void forIntType(IntType t) { _result.append("int"); }
 1655  0 public void forLongType(LongType t) { _result.append("long"); }
 1656  0 public void forFloatType(FloatType t) { _result.append("float"); }
 1657  0 public void forDoubleType(DoubleType t) { _result.append("double"); }
 1658  0 public void forNullType(NullType t) { _result.append("(null)"); }
 1659  6 public void forVoidType(VoidType t) { _result.append("void"); }
 1660  0 public void forTopType(TopType t) { _result.append("(top)"); }
 1661  0 public void forBottomType(BottomType t) { _result.append("(bottom)"); }
 1662   
 1663  4 public void forSimpleArrayType(SimpleArrayType t) {
 1664  4 run(t.ofType());
 1665  4 _result.append("[]");
 1666    }
 1667   
 1668  4 public void forVarargArrayType(VarargArrayType t) {
 1669  4 run(t.ofType());
 1670  4 _result.append("...");
 1671    }
 1672   
 1673  101 public void forSimpleClassType(SimpleClassType t) { appendClassName(t.ofClass()); }
 1674   
 1675  0 public void forRawClassType(RawClassType t) {
 1676  0 _result.append("raw ");
 1677  0 appendClassName(t.ofClass());
 1678    }
 1679   
 1680  41 public void forParameterizedClassType(ParameterizedClassType t) {
 1681  41 Iterator<DJClass> classes = SymbolUtil.outerClassChain(t.ofClass()).iterator();
 1682  41 Iterator<? extends Type> targs = t.typeArguments().iterator();
 1683  41 DJClass c = classes.next();
 1684  41 appendClassName(c);
 1685  41 DJClass inner;
 1686  41 while (c != null) {
 1687  41 inner = classes.hasNext() ? classes.next() : null; // next in the chain, or null if c is last
 1688  41 if (inner == null || !inner.isStatic()) {
 1689  41 Iterable<VariableType> params = c.declaredTypeParameters();
 1690  41 if (!IterUtil.isEmpty(params)) {
 1691  41 _result.append("<");
 1692  41 boolean firstParam = true;
 1693  41 for (VariableType param : params) { // param is ignored -- it's just a counter
 1694  0 if (!firstParam) { _result.append(", "); }
 1695  41 firstParam = false;
 1696  41 run(targs.next());
 1697    }
 1698  41 _result.append(">");
 1699    }
 1700    }
 1701  0 if (inner != null) { _result.append("."); _result.append(inner.declaredName()); }
 1702  41 c = inner;
 1703    }
 1704    }
 1705   
 1706  142 private void appendClassName(DJClass c) {
 1707  142 if (c.isAnonymous()) {
 1708  0 _result.append("anonymous ");
 1709  0 runOnList(c.declaredSupertypes(), " & ");
 1710    }
 1711  142 else { _result.append(SymbolUtil.shortName(c)); }
 1712    }
 1713   
 1714  22 public void forVariableType(VariableType t) {
 1715  22 _result.append(nameForVariable(t));
 1716    }
 1717   
 1718  0 public void forIntersectionType(IntersectionType t) {
 1719  0 int size = IterUtil.sizeOf(t.ofTypes());
 1720  0 if (size == 0) { _result.append("(empty intersect)"); }
 1721  0 else if (size == 1) {
 1722  0 _result.append("(intersect ");
 1723  0 run(IterUtil.first(t.ofTypes()));
 1724  0 _result.append(")");
 1725    }
 1726  0 else { runOnList(t.ofTypes(), " & "); }
 1727    }
 1728   
 1729  0 public void forUnionType(UnionType t) {
 1730  0 int size = IterUtil.sizeOf(t.ofTypes());
 1731  0 if (size == 0) { _result.append("(empty union)"); }
 1732  0 else if (size == 1) {
 1733  0 _result.append("(union ");
 1734  0 run(IterUtil.first(t.ofTypes()));
 1735  0 _result.append(")");
 1736    }
 1737  0 else { runOnList(t.ofTypes(), " | "); }
 1738    }
 1739   
 1740  9 public void forWildcard(Wildcard t) {
 1741  9 _result.append("?");
 1742  9 if (!isEqual(t.symbol().upperBound(), OBJECT)) {
 1743  6 _result.append(" extends ");
 1744  6 run(t.symbol().upperBound());
 1745    }
 1746  9 if (!isEqual(t.symbol().lowerBound(), NULL)) {
 1747  6 _result.append(" super ");
 1748  6 run(t.symbol().lowerBound());
 1749    }
 1750    }
 1751   
 1752    }
 1753   
 1754    }
 1755   
 1756    /**
 1757    * Implementation of member lookup. Subclasses provide an implementation of {@link #declaredMatches},
 1758    * which produces the set of matches for a particular type. Traversal of the type hierarchy
 1759    * is managed here.
 1760    */
 1761    private abstract class MemberFinder<T> {
 1762    /** Test whether a search of the given type produces at least one result. */
 1763  784 public boolean hasMatch(Type t) { return !IterUtil.isEmpty(findFirst(t)); }
 1764    /**
 1765    * Produce the set of matching members least-removed from type t. If t declares at least one
 1766    * match, no supertype recursion takes place.
 1767    */
 1768  962 public PredicateSet<T> findFirst(Type t) { return find(t, false); }
 1769   
 1770    /** Produce all matching members of t (both declared and inherited). */
 1771  286 public PredicateSet<T> findAll(Type t) { return find(t, true); }
 1772   
 1773    /** Get a list of all declared members of t that match. */
 1774    protected abstract Iterable<T> declaredMatches(Type t);
 1775   
 1776    /** Whether the child type inherits the given match from a supertype. */
 1777    protected abstract boolean inherits(Type child, PredicateSet<T> childMatches, T match);
 1778   
 1779  2633 private PredicateSet<T> find(final Type t, final boolean findAll) {
 1780  2633 debug.logStart("t", wrap(t)); try {
 1781   
 1782  2633 final PredicateSet<T> childMatches = CollectUtil.asPredicateSet(declaredMatches(t));
 1783  2633 if (!findAll && !IterUtil.isEmpty(childMatches)) {
 1784    // take snapshot of lazily-constructed set
 1785  432 return CollectUtil.makeSet(childMatches);
 1786    }
 1787    else {
 1788  2201 PredicateSet<T> fromSupers = t.apply(new TypeAbstractVisitor<PredicateSet<T>>() {
 1789   
 1790  0 public PredicateSet<T> defaultCase(Type t) { return CollectUtil.emptySet(); }
 1791   
 1792  0 @Override public PredicateSet<T> forArrayType(ArrayType t) {
 1793  0 return find(CLONEABLE_AND_SERIALIZABLE, findAll);
 1794    }
 1795   
 1796  2099 @Override public PredicateSet<T> forClassType(ClassType t) {
 1797  2099 Type superT = immediateSupertype(t);
 1798  968 if (superT == null) { return CollectUtil.emptySet(); }
 1799  1131 else { return find(superT, findAll); }
 1800    }
 1801   
 1802  0 @Override public PredicateSet<T> forVariableType(VariableType t) {
 1803  0 return find(t.symbol().upperBound(), findAll);
 1804    }
 1805   
 1806  102 @Override public PredicateSet<T> forIntersectionType(IntersectionType t) {
 1807  102 PredicateSet<T> result = CollectUtil.emptySet();
 1808  102 for (Type tSup : t.ofTypes()) {
 1809  254 PredicateSet<T> forSup = find(tSup, findAll);
 1810  254 result = CollectUtil.union(result, forSup);
 1811    }
 1812  102 return result;
 1813    }
 1814   
 1815  0 @Override public PredicateSet<T> forUnionType(UnionType t) {
 1816  0 Iterable<? extends Type> sups = t.ofTypes();
 1817  0 if (IterUtil.isEmpty(sups)) { return CollectUtil.emptySet(); }
 1818    else {
 1819  0 PredicateSet<T> result = find(IterUtil.first(sups), findAll);
 1820  0 for (Type tSup : IterUtil.skipFirst(sups)) {
 1821  0 PredicateSet<T> forSup = find(tSup, findAll);
 1822  0 result = CollectUtil.intersection(result, forSup);
 1823    // don't short-circuit when empty, because the empty test is expensive
 1824    }
 1825  0 return result;
 1826    }
 1827    }
 1828   
 1829    });
 1830  2201 PredicateSet<T> result = CollectUtil.union(childMatches, CollectUtil.filter(fromSupers, new Predicate<T>() {
 1831  767 public boolean contains(T match) { return inherits(t, childMatches, match); }
 1832    }));
 1833    // take snapshot of lazily-constructed sets
 1834  2201 return CollectUtil.makeSet(result);
 1835    }
 1836   
 1837  2633 } finally { debug.logEnd(); }
 1838    }
 1839    }
 1840   
 1841    private class MethodFinder extends MemberFinder<DJMethod> {
 1842    private final String _name;
 1843    private final Access.Module _accessModule;
 1844    private final boolean _onlyStatic;
 1845  286 protected MethodFinder(String name, Access.Module accessModule, boolean onlyStatic) {
 1846  286 _name = name;
 1847  286 _accessModule = accessModule;
 1848  286 _onlyStatic = onlyStatic;
 1849    }
 1850   
 1851    /** Search for matching methods and determine the best applicable instance, if any. */
 1852  286 public FunctionInvocationCandidate<DJMethod>
 1853    findSingleMethod(Type t, Iterable<? extends Type> targs, Iterable<? extends Expression> args,
 1854    Option<Type> expected) throws UnmatchedLookupException {
 1855  286 debug.logStart(new String[]{"t","name","onlyStatic"}, wrap(t), _name, _onlyStatic); try {
 1856   
 1857  286 PredicateSet<DJMethod> candidates = findAll(t);
 1858  286 Iterable<FunctionInvocationCandidate<DJMethod>> best = bestInvocations(candidates, targs, args, expected);
 1859    // TODO: provide more error-message information
 1860  286 int matches = IterUtil.sizeOf(best);
 1861  16 if (matches == 0) { throw new UnmatchedFunctionLookupException(candidates); }
 1862  270 else if (matches > 1) {
 1863  0 Iterable<DJMethod> ms = IterUtil.map(best, new Lambda<FunctionInvocationCandidate<DJMethod>, DJMethod>() {
 1864  0 public DJMethod value(FunctionInvocationCandidate<DJMethod> c) { return c.function(); }
 1865    });
 1866  0 throw new AmbiguousFunctionLookupException(ms);
 1867    }
 1868  270 else { return IterUtil.first(best); }
 1869   
 1870  286 } finally { debug.logEnd(); }
 1871    }
 1872   
 1873  942 protected Iterable<DJMethod> declaredMatches(Type t) {
 1874  942 return t.apply(new TypeAbstractVisitor<Iterable<DJMethod>>() {
 1875  9217 private boolean matches(DJMethod m) {
 1876  9217 return m.declaredName().equals(_name) && !(_onlyStatic && !m.isStatic()) && accessible(m, _accessModule);
 1877    }
 1878  74 @Override public Iterable<DJMethod> defaultCase(Type t) { return IterUtil.empty(); }
 1879  0 @Override public Iterable<DJMethod> forArrayType(ArrayType t) {
 1880  0 if (_name.equals("clone") && !_onlyStatic) {
 1881  0 return IterUtil.<DJMethod>make(new ArrayCloneMethod(t));
 1882    }
 1883  0 else { return IterUtil.empty(); }
 1884    }
 1885  868 @Override public Iterable<DJMethod> forClassType(ClassType t) {
 1886  868 List<DJMethod> result = new LinkedList<DJMethod>();
 1887  868 for (DJMethod m : t.ofClass().declaredMethods()) {
 1888  438 if (matches(m)) { result.add(instantiateMethod(m, t)); }
 1889    }
 1890  868 if (!_onlyStatic && _name.equals("getClass")) {
 1891    // remove Object.getClass(), if it appears, and add a GetClassMethod instance
 1892  0 Iterator<DJMethod> i = result.iterator();
 1893  0 while (i.hasNext()) {
 1894  0 DJMethod m = i.next();
 1895  0 if (!m.isStatic() && m.declaredName().equals("getClass") &&
 1896    OBJECT.ofClass().equals(m.declaringClass()) && IterUtil.isEmpty(m.parameters())) {
 1897  0 i.remove();
 1898  0 break;
 1899    }
 1900    }
 1901  0 result.add(new GetClassMethod(t, StandardTypeSystem.this));
 1902    }
 1903  868 return result;
 1904    }
 1905    });
 1906    }
 1907   
 1908  767 protected boolean inherits(Type child, PredicateSet<DJMethod> childMatches, DJMethod match) {
 1909    // TODO: follow the JLS definition of method inheritance (8.4.8)
 1910  0 if (match.accessibility().equals(Access.PRIVATE)) { return false; }
 1911    else {
 1912  767 for (DJMethod childMethod : childMatches) {
 1913  216 if (overrides(childMethod, match)) { return false; }
 1914    }
 1915  551 return true;
 1916    }
 1917    }
 1918   
 1919    /** True iff child is override-compatible with the parent. (See JLS 8.4.2.) */
 1920  216 private boolean overrides(DJMethod child, DJMethod parent) {
 1921  216 if (child.declaredName().equals(parent.declaredName())) {
 1922  216 Iterable<Type> subParams = SymbolUtil.parameterTypes(child);
 1923  216 Iterable<Type> supParams = SymbolUtil.parameterTypes(parent);
 1924  216 Iterable<VariableType> subTParams = child.typeParameters();
 1925  216 Iterable<VariableType> supTParams = parent.typeParameters();
 1926  216 if (IterUtil.sizeOf(subParams) == IterUtil.sizeOf(supParams)) {
 1927  216 Iterable<? extends Type> supParamsToCompare;
 1928  216 if (IterUtil.isEmpty(subTParams) && !IterUtil.isEmpty(supTParams)) {
 1929  0 supParamsToCompare = IterUtil.map(supParams, ERASE);
 1930    }
 1931  216 else if (IterUtil.sizeOf(subTParams) == IterUtil.sizeOf(supTParams)) {
 1932  216 supParamsToCompare = substitute(supParams, supTParams, subTParams);
 1933    }
 1934  0 else { return false; }
 1935  216 for (Pair<Type, Type> p : IterUtil.zip(subParams, supParamsToCompare)) {
 1936  0 if (!isEqual(p.first(), p.second())) { return false; }
 1937    }
 1938  216 return true;
 1939    }
 1940  0 else { return false; }
 1941    }
 1942  0 else { return false; }
 1943    }
 1944   
 1945    }
 1946   
 1947    private abstract class FieldFinder<T extends FieldReference> extends MemberFinder<T> {
 1948    private final String _name;
 1949    private final Access.Module _accessModule;
 1950    private final boolean _onlyStatic;
 1951  438 protected FieldFinder(String name, Access.Module accessModule, boolean onlyStatic) {
 1952  438 _name = name;
 1953  438 _accessModule = accessModule;
 1954  438 _onlyStatic = onlyStatic;
 1955    }
 1956   
 1957    /** If a single field is produced by findFirst(t), return it; otherwise, throw an exception. */
 1958  178 public T findSingleField(Type t) throws UnmatchedLookupException {
 1959  178 debug.logStart(new String[]{"t","name","onlyStatic"}, wrap(t), _name, _onlyStatic); try {
 1960   
 1961  178 Iterable<T> results = findFirst(t);
 1962    // TODO: provide more error-message information
 1963  178 int matches = IterUtil.sizeOf(results);
 1964  0 if (matches != 1) { throw new UnmatchedLookupException(matches); }
 1965  178 else { return IterUtil.first(results); }
 1966   
 1967  178 } finally { debug.logEnd(); }
 1968    }
 1969   
 1970    protected abstract T makeFieldReference(Type declaringType, DJField field);
 1971   
 1972  444 protected Iterable<T> declaredMatches(Type t) {
 1973  444 Iterable<T> result = t.apply(new TypeAbstractVisitor<Iterable<T>>() {
 1974  326 private boolean matches(DJField f) {
 1975  326 return f.declaredName().equals(_name) && !(_onlyStatic && !f.isStatic()) && accessible(f, _accessModule);
 1976    }
 1977  0 @Override public Iterable<T> defaultCase(Type t) { return IterUtil.empty(); }
 1978  108 @Override public Iterable<T> forArrayType(ArrayType t) {
 1979  108 if (_name.equals("length") && !_onlyStatic) {
 1980  108 return IterUtil.make(makeFieldReference(t, ArrayLengthField.INSTANCE));
 1981    }
 1982  0 else { return IterUtil.empty(); }
 1983    }
 1984  336 @Override public Iterable<T> forClassType(ClassType t) {
 1985  336 for (DJField f : t.ofClass().declaredFields()) {
 1986  324 if (matches(f)) { return IterUtil.make(makeFieldReference(t, f)); }
 1987    }
 1988  12 return IterUtil.empty();
 1989    }
 1990    });
 1991  444 return result;
 1992    }
 1993   
 1994  0 protected boolean inherits(Type child, PredicateSet<T> childMatches, T match) {
 1995    // TODO: follow the JLS definition of field inheritance (8.3)
 1996  0 return childMatches.isEmpty() && !match.field().accessibility().equals(Access.PRIVATE);
 1997    }
 1998   
 1999    }
 2000   
 2001    private class ClassFinder extends MemberFinder<ClassType> {
 2002    private final String _name;
 2003    private final Iterable<? extends Type> _typeArgs;
 2004    private final Access.Module _accessModule;
 2005    private final boolean _onlyStatic;
 2006  524 protected ClassFinder(String name, Iterable<? extends Type> typeArgs, Access.Module accessModule,
 2007    boolean onlyStatic) {
 2008  524 _name = name;
 2009  524 _typeArgs = typeArgs;
 2010  524 _accessModule = accessModule;
 2011  524 _onlyStatic = onlyStatic;
 2012    }
 2013   
 2014    /**
 2015    * If a single class is produced by findFirst(t) and the type arguments are valid, return the
 2016    * type; otherwise, throw an exception.
 2017    */
 2018  0 public ClassType findSingleClass(Type t) throws InvalidTypeArgumentException, UnmatchedLookupException {
 2019  0 debug.logStart(new String[]{"t","name","typeArgs", "onlyStatic"},
 2020  0 wrap(t), _name, wrap(_typeArgs), _onlyStatic); try {
 2021   
 2022  0 Iterable<ClassType> results = findFirst(t);
 2023    // TODO: provide more error-message information
 2024  0 int matches = IterUtil.sizeOf(results);
 2025  0 if (matches != 1) { throw new UnmatchedLookupException(matches); }
 2026    else {
 2027  0 ClassType result = IterUtil.first(results);
 2028  0 final Iterable<VariableType> params = SymbolUtil.allTypeParameters(result.ofClass());
 2029  0 try {
 2030  0 return result.apply(new TypeAbstractVisitor<ClassType>() {
 2031  0 public ClassType defaultCase(Type t) { throw new IllegalArgumentException(); }
 2032   
 2033  0 @Override public ClassType forSimpleClassType(SimpleClassType t) {
 2034  0 if (IterUtil.isEmpty(params)) { return t; }
 2035  0 else { return new RawClassType(t.ofClass()); }
 2036    }
 2037   
 2038  0 @Override public ClassType forRawClassType(RawClassType t) {
 2039  0 return t;
 2040    }
 2041   
 2042  0 @Override public ClassType forParameterizedClassType(ParameterizedClassType t) {
 2043  0 try {
 2044  0 if (IterUtil.sizeOf(params) != IterUtil.sizeOf(t.typeArguments())) {
 2045  0 throw new InvalidTypeArgumentException();
 2046    }
 2047  0 return t;
 2048    }
 2049  0 catch (InvalidTypeArgumentException e) { throw new WrappedException(e); }
 2050    }
 2051    });
 2052    }
 2053    catch (WrappedException e) {
 2054  0 if (e.getCause() instanceof InvalidTypeArgumentException) {
 2055  0 throw (InvalidTypeArgumentException) e.getCause();
 2056    }
 2057  0 else { throw e; }
 2058    }
 2059    }
 2060   
 2061  0 } finally { debug.logEnd(); }
 2062    }
 2063   
 2064    /**
 2065    * The given type arguments are applied to the result, but no checks are
 2066    * made for their correctness (a ParameterizedClassType result may have the wrong number of
 2067    * arguments, including the case of missing arguments from a raw outer type; a SimpleClassType
 2068    * result may be missing arguments).
 2069    */
 2070  1247 protected Iterable<ClassType> declaredMatches(Type t) {
 2071  1247 return t.apply(new TypeAbstractVisitor<Iterable<ClassType>>() {
 2072   
 2073  28 @Override public Iterable<ClassType> defaultCase(Type t) { return IterUtil.empty(); }
 2074   
 2075  1219 @Override public Iterable<ClassType> forClassType(final ClassType t) {
 2076   
 2077  1219 Predicate<DJClass> matchInner = new Predicate<DJClass>() {
 2078  0 public boolean contains(DJClass c) {
 2079  0 return !c.isAnonymous() && c.declaredName().equals(_name) && !(_onlyStatic && !c.isStatic()) &&
 2080    accessible(c, _accessModule);
 2081    }
 2082    };
 2083  1219 Lambda<DJClass, ClassType> makeType = new Lambda<DJClass, ClassType>() {
 2084  0 public ClassType value(DJClass c) {
 2085  0 ClassType dynamicOuter; // may be null
 2086  0 if (c.isStatic()) { dynamicOuter = SymbolUtil.dynamicOuterClassType(t); }
 2087  0 else { dynamicOuter = t; }
 2088  0 if (dynamicOuter instanceof ParameterizedClassType) {
 2089  0 Iterable<? extends Type> outerTypeArgs = ((ParameterizedClassType) dynamicOuter).typeArguments();
 2090  0 return new ParameterizedClassType(c, IterUtil.compose(outerTypeArgs, _typeArgs));
 2091    }
 2092  0 else if (dynamicOuter instanceof RawClassType) {
 2093    // malformed if type args is nonempty -- that should be caught by findSingleClass
 2094  0 return IterUtil.isEmpty(_typeArgs) ? new RawClassType(c) : new ParameterizedClassType(c, _typeArgs);
 2095    }
 2096    else {
 2097  0 return IterUtil.isEmpty(_typeArgs) ? new SimpleClassType(c) : new ParameterizedClassType(c, _typeArgs);
 2098    }
 2099    }
 2100    };
 2101  1219 return IterUtil.map(IterUtil.filter(t.ofClass().declaredClasses(), matchInner), makeType);
 2102    }
 2103   
 2104    });
 2105    }
 2106   
 2107  0 protected boolean inherits(Type child, PredicateSet<ClassType> childMatches, ClassType match) {
 2108    // TODO: follow the JLS definition of class inheritance (8.5)
 2109  0 return childMatches.isEmpty() && !match.ofClass().accessibility().equals(Access.PRIVATE);
 2110    }
 2111   
 2112    }
 2113   
 2114    private class FunctionInvocationCandidate<F extends Function> {
 2115    private final F _f;
 2116    private final SignatureMatcher _matcher;
 2117   
 2118  1546 public FunctionInvocationCandidate(F f, Iterable<? extends Type> targs,
 2119    Iterable<? extends Expression> args, Option<Type> expected) {
 2120  1546 _f = f;
 2121  1546 _matcher = makeMatcher(f.typeParameters(), targs, SymbolUtil.parameterTypes(f), args, f.returnType(), expected);
 2122    }
 2123   
 2124  821 public F function() { return _f; }
 2125  821 public Iterable<? extends Type> typeArguments() { return _matcher.typeArguments(); }
 2126  821 public Iterable<? extends Expression> arguments() { return _matcher.arguments(); }
 2127   
 2128  821 public SubstitutionMap substitution() {
 2129  821 return new SubstitutionMap(_f.typeParameters(), _matcher.typeArguments());
 2130    }
 2131   
 2132  1556 private SignatureMatcher makeMatcher(Iterable<? extends VariableType> tparams,
 2133    Iterable<? extends Type> targs,
 2134    Iterable<? extends Type> params,
 2135    Iterable<? extends Expression> args,
 2136    Type returned, Option<Type> expected) {
 2137    // Note: per the JLS, we allow the presence of (ignored) targs when tparams is empty
 2138  1556 int argCount = IterUtil.sizeOf(args);
 2139  1556 int paramCount = IterUtil.sizeOf(params);
 2140  1556 if (argCount == paramCount - 1) {
 2141  216 if (IterUtil.isEmpty(tparams)) {
 2142  216 return new EmptyVarargMatcher(params, args, tparams, EMPTY_TYPE_ITERABLE);
 2143    }
 2144  0 else if (IterUtil.isEmpty(targs) || !_useExplicitTypeArgs) {
 2145  0 return new EmptyVarargInferenceMatcher(params, args, tparams, returned, expected);
 2146    }
 2147  0 else if (IterUtil.sizeOf(tparams) == IterUtil.sizeOf(targs) && inBounds(tparams, targs)) {
 2148  0 return new EmptyVarargMatcher(substitute(params, tparams, targs), args, tparams, targs);
 2149    }
 2150  0 else { return NullMatcher.INSTANCE; }
 2151    }
 2152  1340 else if (argCount == paramCount) {
 2153  1141 if (IterUtil.isEmpty(tparams)) {
 2154  1116 return new SimpleMatcher(params, args, tparams, EMPTY_TYPE_ITERABLE);
 2155    }
 2156  25 else if (IterUtil.isEmpty(targs) || !_useExplicitTypeArgs) {
 2157  25 return new InferenceMatcher(params, args, tparams, returned, expected);
 2158    }
 2159  0 else if (IterUtil.sizeOf(tparams) == IterUtil.sizeOf(targs) && inBounds(tparams, targs)) {
 2160  0 return new SimpleMatcher(substitute(params, tparams, targs), args, tparams, targs);
 2161    }
 2162  0 else { return NullMatcher.INSTANCE; }
 2163    }
 2164  199 else if (argCount > paramCount && paramCount >= 1) {
 2165  12 if (IterUtil.isEmpty(tparams)) {
 2166  12 return new MultiVarargMatcher(params, args, tparams, EMPTY_TYPE_ITERABLE);
 2167    }
 2168  0 else if (IterUtil.isEmpty(targs) || !_useExplicitTypeArgs) {
 2169  0 return new MultiVarargInferenceMatcher(params, args, tparams, returned, expected);
 2170    }
 2171  0 else if (IterUtil.sizeOf(tparams) == IterUtil.sizeOf(targs) && inBounds(tparams, targs)) {
 2172  0 return new MultiVarargMatcher(substitute(params, tparams, targs), args, tparams, targs);
 2173    }
 2174  0 else { return NullMatcher.INSTANCE; }
 2175    }
 2176  187 else { return NullMatcher.INSTANCE; }
 2177    }
 2178   
 2179    /**
 2180    * True iff this declaration's parameters could be used to invoke c. Must only be invoked with matched
 2181    * SignatureMatchers. This relation is defined in JLS 15.12.2.5.
 2182    */
 2183  10 public boolean moreSpecificThan(FunctionInvocationCandidate<F> c) {
 2184  10 Iterable<Type> supParams = SymbolUtil.parameterTypes(c._f);
 2185  10 Iterable<Type> subParams = SymbolUtil.parameterTypes(_f);
 2186  10 if (SymbolUtil.isVararg(c._f)) {
 2187    // Adjust param type lists to match arities, if possible. Can't use SignatureMatcher.matchesWithVarargs()
 2188    // because it uses boxing, which is not allowed here.
 2189  0 int supArity = IterUtil.sizeOf(supParams);
 2190  0 int subArity = IterUtil.sizeOf(subParams);
 2191  0 if (SymbolUtil.isVararg(_f)) {
 2192  0 if (subArity < supArity) { // fill in extra sub args
 2193  0 Iterable<Type> prefixSubs = IterUtil.skipLast(subParams);
 2194  0 Type lastSub = IterUtil.last(subParams);
 2195  0 Iterable<Type> subExtras = IterUtil.copy(((ArrayType) lastSub).ofType(), supArity-subArity);
 2196  0 subParams = IterUtil.compose(IterUtil.compose(prefixSubs, subExtras), lastSub);
 2197    }
 2198  0 else if (subArity > supArity) {
 2199  0 Iterable<Type> prefixSups = IterUtil.skipLast(supParams);
 2200  0 Type lastSup = IterUtil.last(supParams);
 2201  0 Iterable<Type> supExtras = IterUtil.copy(((ArrayType) lastSup).ofType(), subArity-supArity);
 2202  0 supParams = IterUtil.compose(IterUtil.compose(prefixSups, supExtras), lastSup);
 2203    }
 2204    // if they're equal, no adjustments are needed
 2205    }
 2206    else {
 2207    // This case doesn't occur in practice, because "more specific" is only used to compare
 2208    // methods that all match in the same phase (directly, with boxing, or with varargs).
 2209  0 if (subArity < supArity) { supParams = IterUtil.skipLast(supParams); } // allow sub to elide the vararg param
 2210  0 else if (subArity > supArity) {
 2211  0 Iterable<Type> prefixSups = IterUtil.skipLast(supParams);
 2212  0 Type lastSup = IterUtil.last(supParams);
 2213  0 int varargArgs = subArity-(supArity-1); // expect this many args of the vararg type
 2214  0 supParams = IterUtil.compose(prefixSups, IterUtil.copy(((ArrayType) lastSup).ofType(), varargArgs));
 2215    }
 2216    // if they're equal, no adjustments are needed
 2217    // (If lastSup is T..., lastSub might be a subtype of T or of T[]. For the purposes of
 2218    // "more specific", we arbitrarily require it to be a subtype of T[].)
 2219    }
 2220    }
 2221  10 SignatureMatcher m = makeMatcher(c._f.typeParameters(), EMPTY_TYPE_ITERABLE, supParams,
 2222    IterUtil.mapSnapshot(subParams, EMPTY_EXPRESSION_FOR_TYPE),
 2223    BOTTOM, NONE_TYPE_OPTION);
 2224  10 return m.matches() || _boxingInMostSpecific && m.matchesWithBoxing();
 2225    }
 2226   
 2227    }
 2228   
 2229    /**
 2230    * Get a minimal sublist of the invocation candidates that are best matches. Only candidates that
 2231    * match in the same stage ({@code matches()}, {@code matchesWithBoxing()}, or {@code matchesWithVarargs()})
 2232    * may appear in the result. Of those that match, a list with most specific signatures is returned.
 2233    */
 2234  838 private <F extends Function>
 2235    Iterable<FunctionInvocationCandidate<F>> bestInvocations(Iterable<F> functions,
 2236    final Iterable<? extends Type> targs,
 2237    final Iterable<? extends Expression> args,
 2238    final Option<Type> expected) {
 2239    // This would be a static member of FunctionInvocationCandidate if that were legal;
 2240    // it accesses the _matcher field as if it were.
 2241  838 Iterable<FunctionInvocationCandidate<F>> candidates = IterUtil.mapSnapshot(functions,
 2242    new Lambda<F, FunctionInvocationCandidate<F>>() {
 2243  1546 public FunctionInvocationCandidate<F> value(F f) {
 2244  1546 return new FunctionInvocationCandidate<F>(f, targs, args, expected);
 2245    }
 2246    });
 2247  838 List<FunctionInvocationCandidate<F>> matches = new LinkedList<FunctionInvocationCandidate<F>>();
 2248  838 for (FunctionInvocationCandidate<F> c : candidates) {
 2249  811 if (c._matcher.matches()) { matches.add(c); }
 2250    }
 2251  838 if (matches.isEmpty()) {
 2252  37 for (FunctionInvocationCandidate<F> c : candidates) {
 2253  0 if (c._matcher.matchesWithBoxing()) { matches.add(c); }
 2254    }
 2255    }
 2256  838 if (matches.isEmpty()) {
 2257  37 for (FunctionInvocationCandidate<F> c : candidates) {
 2258  20 if (c._matcher.matchesWithVarargs()) { matches.add(c); }
 2259    }
 2260    }
 2261  838 return CollectUtil.minList(matches, new Order<FunctionInvocationCandidate<F>>() {
 2262  10 public boolean contains(FunctionInvocationCandidate<F> c1, FunctionInvocationCandidate<F> c2) {
 2263  10 return c1.moreSpecificThan(c2);
 2264    }
 2265    });
 2266    }
 2267   
 2268    private static final Lambda<Type, Expression> EMPTY_EXPRESSION_FOR_TYPE = new Lambda<Type, Expression>() {
 2269  19 public Expression value(Type t) {
 2270  19 Expression result = TypeUtil.makeEmptyExpression();
 2271  19 NodeProperties.setType(result, t);
 2272  19 return result;
 2273    }
 2274    };
 2275   
 2276    /**
 2277    * Instantiate a method based on its enclosing type. Would be static in MethodInvocationCandidate
 2278    * if that were allowed.
 2279    */
 2280  438 private DJMethod instantiateMethod(final DJMethod declaredMethod, Type declaringType) {
 2281  438 Type dynamicContext;
 2282  438 if (declaredMethod.isStatic()) {
 2283  216 if (declaringType instanceof ClassType) {
 2284  216 dynamicContext = SymbolUtil.dynamicOuterClassType((ClassType) declaringType);
 2285    }
 2286  0 else { dynamicContext = null; }
 2287    }
 2288  222 else { dynamicContext = declaringType; }
 2289  216 if (dynamicContext == null) { return declaredMethod; }
 2290    else {
 2291  222 return dynamicContext.apply(new TypeAbstractVisitor<DJMethod>() {
 2292  153 @Override public DJMethod defaultCase(Type dynamicContext) { return declaredMethod; }
 2293  0 @Override public DJMethod forRawClassType(RawClassType dynamicContext) {
 2294    // TODO: raw member access warnings
 2295  0 return new ErasedMethod(declaredMethod);
 2296    }
 2297  69 @Override public DJMethod forParameterizedClassType(ParameterizedClassType dynamicContext) {
 2298  69 ParameterizedClassType dynamicContextCap = capture(dynamicContext);
 2299  69 Iterable<VariableType> tparams = SymbolUtil.allTypeParameters(dynamicContextCap.ofClass());
 2300  69 return new InstantiatedMethod(declaredMethod, tparams, dynamicContextCap.typeArguments());
 2301    }
 2302    });
 2303    }
 2304    }
 2305   
 2306    private static abstract class DelegatingFunction<T extends Function> implements Function {
 2307    protected final T _delegate;
 2308  289 protected DelegatingFunction(T delegate) { _delegate = delegate; }
 2309   
 2310  57 public String declaredName() { return _delegate.declaredName(); }
 2311  333 public Iterable<LocalVariable> parameters() {
 2312  333 return IterUtil.mapSnapshot(IterUtil.zip(_delegate.parameters(), parameterTypes()),
 2313    new Lambda<Pair<LocalVariable, Type>, LocalVariable>() {
 2314  289 public LocalVariable value(Pair<LocalVariable, Type> p) {
 2315  289 return new LocalVariable(p.first().declaredName(), p.second(), p.first().isFinal());
 2316    }
 2317    });
 2318    }
 2319   
 2320    public abstract Iterable<VariableType> typeParameters();
 2321    public abstract Type returnType();
 2322    public abstract Iterable<Type> thrownTypes();
 2323    protected abstract Iterable<? extends Type> parameterTypes();
 2324    }
 2325   
 2326    private static abstract class DelegatingMethod extends DelegatingFunction<DJMethod> implements DJMethod {
 2327  69 protected DelegatingMethod(DJMethod delegate) { super(delegate); }
 2328  0 public DJClass declaringClass() { return _delegate.declaringClass(); }
 2329  0 public boolean isStatic() { return _delegate.isStatic(); }
 2330  0 public boolean isAbstract() { return _delegate.isAbstract(); }
 2331  0 public boolean isFinal() { return _delegate.isFinal(); }
 2332  47 public Access accessibility() { return _delegate.accessibility(); }
 2333  0 public Access.Module accessModule() { return _delegate.accessModule(); }
 2334  0 public DJMethod declaredSignature() { return _delegate.declaredSignature(); }
 2335  34 public Object evaluate(Object receiver, Iterable<Object> args, RuntimeBindings bindings, Options options)
 2336    throws EvaluatorException {
 2337  34 return _delegate.evaluate(receiver, args, bindings, options);
 2338    }
 2339    }
 2340   
 2341    private class ErasedMethod extends DelegatingMethod {
 2342  0 public ErasedMethod(DJMethod m) { super(m); }
 2343  0 public Iterable<VariableType> typeParameters() { return IterUtil.empty(); }
 2344  0 public Type returnType() { return erase(_delegate.returnType()); }
 2345  0 public Iterable<Type> thrownTypes() { return IterUtil.mapSnapshot(_delegate.thrownTypes(), ERASE); }
 2346  0 protected Iterable<Type> parameterTypes() {
 2347  0 return IterUtil.mapSnapshot(SymbolUtil.parameterTypes(_delegate), ERASE);
 2348    }
 2349    }
 2350   
 2351    private class InstantiatedMethod extends DelegatingMethod {
 2352    private final SubstitutionMap _sigma;
 2353    private final Iterable<VariableType> _tparams;
 2354  69 public InstantiatedMethod(DJMethod m, Iterable<VariableType> classTParams, Iterable<? extends Type> classTArgs) {
 2355  69 super(m);
 2356  69 Pair<Iterable<VariableType>, SubstitutionMap> p = instantiateTypeParameters(m, classTParams, classTArgs);
 2357  69 _tparams = p.first();
 2358  69 _sigma = p.second();
 2359    }
 2360   
 2361  143 public Type returnType() { return substitute(_delegate.returnType(), _sigma); }
 2362  155 public Iterable<VariableType> typeParameters() { return _tparams; }
 2363  43 public Iterable<Type> thrownTypes() { return IterUtil.relax(substitute(_delegate.thrownTypes(), _sigma)); }
 2364  112 public Iterable<? extends Type> parameterTypes() {
 2365  112 return substitute(SymbolUtil.parameterTypes(_delegate), _sigma);
 2366    }
 2367  0 public String toString() {
 2368  0 TypePrinter p = typePrinter();
 2369  0 return "InstantiatedMethod(" + p.print(this) + ")";
 2370    }
 2371    }
 2372   
 2373    private static abstract class DelegatingConstructor extends DelegatingFunction<DJConstructor>
 2374    implements DJConstructor {
 2375  220 protected DelegatingConstructor(DJConstructor delegate) { super(delegate); }
 2376  0 public DJClass declaringClass() { return _delegate.declaringClass(); }
 2377  220 public Type returnType() { return _delegate.returnType(); }
 2378  266 public Access accessibility() { return _delegate.accessibility(); }
 2379  0 public Access.Module accessModule() { return _delegate.accessModule(); }
 2380  7 public DJConstructor declaredSignature() { return _delegate.declaredSignature(); }
 2381  71 public Object evaluate(Object outer, Iterable<Object> args, RuntimeBindings bindings, Options options)
 2382    throws EvaluatorException {
 2383  71 return _delegate.evaluate(outer, args, bindings, options);
 2384    }
 2385    }
 2386   
 2387    private class ErasedConstructor extends DelegatingConstructor {
 2388  0 public ErasedConstructor(DJConstructor k) { super(k); }
 2389  0 public Iterable<VariableType> typeParameters() { return IterUtil.empty(); }
 2390  0 public Iterable<Type> thrownTypes() { return IterUtil.mapSnapshot(_delegate.thrownTypes(), ERASE); }
 2391  0 protected Iterable<Type> parameterTypes() {
 2392  0 return IterUtil.mapSnapshot(SymbolUtil.parameterTypes(_delegate), ERASE);
 2393    }
 2394  0 public String toString() { return "ErasedConstructor(" + declaredName() + ")"; }
 2395    }
 2396   
 2397    private class InstantiatedConstructor extends DelegatingConstructor {
 2398    private final SubstitutionMap _sigma;
 2399    private final Iterable<VariableType> _tparams;
 2400  220 public InstantiatedConstructor(DJConstructor k, Iterable<VariableType> classTParams,
 2401    Iterable<? extends Type> classTArgs) {
 2402  220 super(k);
 2403  220 Pair<Iterable<VariableType>, SubstitutionMap> p = instantiateTypeParameters(k, classTParams, classTArgs);
 2404  220 _tparams = p.first();
 2405  220 _sigma = p.second();
 2406    }
 2407   
 2408  433 public Iterable<VariableType> typeParameters() { return _tparams; }
 2409  212 public Iterable<Type> thrownTypes() { return IterUtil.relax(substitute(_delegate.thrownTypes(), _sigma)); }
 2410  221 public Iterable<? extends Type> parameterTypes() {
 2411  221 return substitute(SymbolUtil.parameterTypes(_delegate), _sigma);
 2412    }
 2413  0 public String toString() { return "InstantiatedConstructor(" + declaredName() + ")"; }
 2414    }
 2415   
 2416    /** Create new type parameters for function {@code f} with bounds instantiated by the given substitution. */
 2417  289 private Pair<Iterable<VariableType>, SubstitutionMap>
 2418    instantiateTypeParameters(Function f,
 2419    Iterable<? extends VariableType> enclosingTParams,
 2420    Iterable<? extends Type> enclosingTArgs) {
 2421  289 Iterable<VariableType> origTParams = f.typeParameters();
 2422  289 Iterable<VariableType> tparams = IterUtil.mapSnapshot(origTParams, new Lambda<VariableType, VariableType>() {
 2423  0 public VariableType value(VariableType var) {
 2424  0 return new VariableType(new BoundedSymbol(new Object(), var.symbol().name()));
 2425    }
 2426    });
 2427  289 SubstitutionMap sigma = new SubstitutionMap(IterUtil.compose(enclosingTParams, origTParams),
 2428    IterUtil.compose(enclosingTArgs, tparams));
 2429  289 for (Pair<VariableType, VariableType> p : IterUtil.zip(origTParams, tparams)) {
 2430  0 VariableType origParam = p.first();
 2431  0 VariableType newParam = p.second();
 2432  0 newParam.symbol().initializeUpperBound(substitute(origParam.symbol().upperBound(), sigma));
 2433  0 newParam.symbol().initializeLowerBound(substitute(origParam.symbol().lowerBound(), sigma));
 2434    }
 2435  289 return Pair.make(tparams, sigma);
 2436    }
 2437   
 2438    /**
 2439    * A wrapper to optimize the three-stage method-signature matching algorithm. Clients are
 2440    * assumed to invoke the methods {@code matches}, {@code matchesWithBoxing}, and
 2441    * {@code matchesWithVarargs} in that order, and only if the previous match attempt failed;
 2442    * other accessor methods provide the results of a match <em>after</em> one of the match methods
 2443    * returns {@code true}.
 2444    */
 2445    private static abstract class SignatureMatcher {
 2446    /** Must be invoked first */
 2447    public abstract boolean matches();
 2448   
 2449    /** Must only be invoked after {@link #matches()} */
 2450    public abstract boolean matchesWithBoxing();
 2451   
 2452    /** Must only be invoked after {@link #matchesWithBoxing} */
 2453    public abstract boolean matchesWithVarargs();
 2454   
 2455    /** Must only be invoked after one of the match() methods returns {@code true} */
 2456    public abstract Iterable<? extends Type> typeArguments();
 2457   
 2458    /** Must only be invoked after one of the match() methods returns {@code true} */
 2459    public abstract Iterable<? extends Expression> arguments();
 2460    }
 2461   
 2462    private static class NullMatcher extends SignatureMatcher {
 2463    public static final NullMatcher INSTANCE = new NullMatcher();
 2464  1 private NullMatcher() {}
 2465  187 public boolean matches() { return false; }
 2466  4 public boolean matchesWithBoxing() { return false; }
 2467  4 public boolean matchesWithVarargs() { return false; }
 2468  0 public Iterable<? extends Type> typeArguments() { throw new IllegalStateException(); }
 2469  0 public Iterable<? extends Expression> arguments() { throw new IllegalStateException(); }
 2470    }
 2471   
 2472    // cannot be defined statically, because it relies on the definition of non-static methods
 2473    private class SimpleMatcher extends SignatureMatcher {
 2474    protected Iterable<? extends Type> _params;
 2475    protected Iterable<? extends Expression> _args;
 2476    protected Iterable<? extends VariableType> _tparams;
 2477    protected Iterable<? extends Type> _targs;
 2478    protected Type _paramForVarargs; // set at some point before matchesWithVarargs()
 2479    protected Expression _argForVarargs; // set at some point before matchesWithVarargs(); not boxed
 2480    protected boolean _matchesAllButLast; // true if matchesWithBoxing() is true on all but the last arg
 2481   
 2482    /** Assumes {@code params.size() == args.size()} */
 2483  1369 public SimpleMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2484    Iterable<? extends VariableType> tparams, Iterable<? extends Type> targs) {
 2485  1369 _params = params;
 2486  1369 _args = args;
 2487  1369 _tparams = tparams;
 2488  1369 _targs = targs;
 2489    }
 2490   
 2491  1642 public Iterable<? extends Type> typeArguments() { return _targs; }
 2492  821 public Iterable<? extends Expression> arguments() { return _args; }
 2493   
 2494  1135 public boolean matches() {
 2495  1135 Iterator<? extends Type> pI = _params.iterator();
 2496  1135 Iterator<? extends Expression> aI = _args.iterator();
 2497  1135 while (pI.hasNext()) {
 2498    // TODO: Allow unchecked conversion of raw types
 2499  1062 if (!isSubtype(NodeProperties.getType(aI.next()), pI.next())) {
 2500  321 _matchesAllButLast = !pI.hasNext();
 2501  321 return false;
 2502    }
 2503    }
 2504  814 return true;
 2505    }
 2506   
 2507  11 public boolean matchesWithBoxing() { return boxArgs() && matches(); }
 2508   
 2509  11 public boolean matchesWithVarargs() {
 2510  11 if (_matchesAllButLast && _paramForVarargs instanceof VarargArrayType) {
 2511  4 ArrayType arrayT = (ArrayType) substitute(_paramForVarargs, _tparams, _targs);
 2512  4 Type elementT = arrayT.ofType();
 2513  4 _argForVarargs = boxingConvert(_argForVarargs, elementT);
 2514    // TODO: Allow unchecked conversion of raw types?
 2515  4 if (isSubtype(NodeProperties.getType(_argForVarargs), elementT)) {
 2516  4 Expression newArg = makeArray(arrayT, IterUtil.make(_argForVarargs));
 2517  4 _args = IterUtil.compose(IterUtil.skipLast(_args), newArg);
 2518  4 return true;
 2519    }
 2520    }
 2521  7 return false;
 2522    }
 2523   
 2524    /**
 2525    * Update {@code _args} with the boxed or unboxed versions of the arguments; set {@link #_paramForVarargs}
 2526    * and {@link #_argForVarargs} before performing the conversion on the last argument
 2527    *
 2528    * @return {@code true} iff the result of the conversion is different from the original set of arguments
 2529    */
 2530  29 protected boolean boxArgs() {
 2531  29 Iterable<Expression> newArgs = EMPTY_EXPRESSION_ITERABLE;
 2532  29 boolean result = false;
 2533  29 Iterator<? extends Type> pI = _params.iterator();
 2534  29 Iterator<? extends Expression> aI = _args.iterator();
 2535  29 while (pI.hasNext()) {
 2536  22 Type pT = pI.next();
 2537  22 Expression aE = aI.next();
 2538  21 if (!pI.hasNext()) { _paramForVarargs = pT; _argForVarargs = aE; }
 2539  22 Expression newArg = boxingConvert(aE, pT);
 2540  3 if (newArg != aE) { result = true; }
 2541  22 newArgs = IterUtil.compose(newArgs, newArg);
 2542    }
 2543  3 if (result) { _args = newArgs; }
 2544  29 return result;
 2545    }
 2546   
 2547    /** @return The boxed or unboxed version of {@code e}, as necessary, or {@code e}, untouched */
 2548  71 protected Expression boxingConvert(Expression exp, Type target) {
 2549  71 Type t = NodeProperties.getType(exp);
 2550  71 if (isPrimitive(target) && isPrimitiveConvertible(t)) {
 2551  16 try { return makePrimitive(exp); }
 2552  0 catch (UnsupportedConversionException e) { throw new RuntimeException("isPrimitiveConvertible() lied"); }
 2553    }
 2554  55 else if (isReference(target) && isReferenceConvertible(t)) {
 2555  55 try { return makeReference(exp); }
 2556  0 catch (UnsupportedConversionException e) { throw new RuntimeException("isReferenceConvertible() lied"); }
 2557    }
 2558  0 else { return exp; }
 2559    }
 2560   
 2561    }
 2562   
 2563    // cannot be defined statically, because it relies on the definition of non-static methods
 2564    private class InferenceMatcher extends SimpleMatcher {
 2565   
 2566    protected final Type _returned;
 2567    protected final Option<Type> _expected;
 2568   
 2569    /** Assumes {@code params.size() == args.size()} */
 2570  25 public InferenceMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2571    Iterable<? extends VariableType> tparams,
 2572    Type returned, Option<Type> expected) {
 2573  25 super(params, args, tparams, null);
 2574  25 _returned = returned;
 2575  25 if (expected.isSome()) {
 2576  25 Expression exp = TypeUtil.makeEmptyExpression();
 2577  25 NodeProperties.setType(exp, expected.unwrap());
 2578  25 _expected = Option.some(NodeProperties.getType(boxingConvert(exp, _returned)));
 2579    }
 2580  0 else { _expected = expected; }
 2581    }
 2582   
 2583  25 @Override public boolean matches() {
 2584  25 Iterable<Type> argTypes = IterUtil.mapSnapshot(_args, NodeProperties.NODE_TYPE);
 2585  25 _targs = inferTypeArguments(_tparams, _params, _returned, argTypes, _expected);
 2586  25 return (_targs != null);
 2587    }
 2588   
 2589  2 @Override public boolean matchesWithBoxing() {
 2590    // We perform boxing based on the uninstantiated parameter types, but that's okay --
 2591    // free variables with reference bounds will be treated as references
 2592  2 return boxArgs() && matches(); // matches() infers new type arguments
 2593    }
 2594   
 2595  2 @Override public boolean matchesWithVarargs() {
 2596    // We ignore _matchesAllButLast -- it's possible that the new targs will allow a match that
 2597    // didn't work before
 2598  2 if (_paramForVarargs instanceof VarargArrayType) {
 2599  0 ArrayType arrayT = (ArrayType) _paramForVarargs;
 2600  0 Type elementT = arrayT.ofType();
 2601  0 _argForVarargs = boxingConvert(_argForVarargs, elementT);
 2602  0 Iterable<Expression> inferenceArgs = IterUtil.compose(IterUtil.skipLast(_args), _argForVarargs);
 2603  0 Iterable<Type> argTypes = IterUtil.mapSnapshot(inferenceArgs, NodeProperties.NODE_TYPE);
 2604  0 Iterable<Type> paramTypes = IterUtil.compose(IterUtil.skipLast(_params), elementT);
 2605  0 _targs = inferTypeArguments(_tparams, paramTypes, _returned, argTypes, _expected);
 2606  0 if (_targs != null) {
 2607  0 Expression newArg = makeArray((ArrayType) substitute(arrayT, _tparams, _targs),
 2608    IterUtil.make(_argForVarargs));
 2609  0 _args = IterUtil.compose(IterUtil.skipLast(_args), newArg);
 2610  0 return true;
 2611    }
 2612    }
 2613  2 return false;
 2614    }
 2615    }
 2616   
 2617    // cannot be defined statically, because it relies on the definition of non-static methods
 2618    private class EmptyVarargMatcher extends SimpleMatcher {
 2619   
 2620    // Can't use _paramForVarargs, because SimpleMatcher doesn't know about the final parameter
 2621    private Type _varargParam;
 2622   
 2623    /** Assumes {@code params.size() - 1 == args.size()} */
 2624  216 public EmptyVarargMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2625    Iterable<? extends VariableType> tparams, Iterable<? extends Type> targs) {
 2626  216 super(params, args, tparams, targs);
 2627  216 _varargParam = IterUtil.last(_params);
 2628  216 _params = IterUtil.skipLast(_params);
 2629    }
 2630   
 2631  216 @Override public boolean matches() { return false; }
 2632  8 @Override public boolean matchesWithBoxing() { return false; }
 2633   
 2634  8 @Override public boolean matchesWithVarargs() {
 2635  8 if (_varargParam instanceof VarargArrayType) {
 2636  8 boxArgs();
 2637  8 if (super.matches()) {
 2638  8 _params = IterUtil.compose(_params, _varargParam);
 2639  8 ArrayType arrayT = (ArrayType) substitute(_varargParam, _tparams, _targs);
 2640  8 _args = IterUtil.compose(_args, makeArray(arrayT, EMPTY_EXPRESSION_ITERABLE));
 2641  8 return true;
 2642    }
 2643    }
 2644  0 return false;
 2645    }
 2646   
 2647    }
 2648   
 2649    // cannot be defined statically, because it relies on the definition of non-static methods
 2650    private class EmptyVarargInferenceMatcher extends InferenceMatcher {
 2651   
 2652    // Can't use _paramForVarargs, because SimpleMatcher doesn't know about the final parameter
 2653    private Type _varargParam;
 2654   
 2655    /** Assumes {@code params.size() - 1 == args.size()} */
 2656  0 public EmptyVarargInferenceMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2657    Iterable<? extends VariableType> tparams,
 2658    Type returned, Option<Type> expected) {
 2659  0 super(params, args, tparams, returned, expected);
 2660  0 _varargParam = IterUtil.last(_params);
 2661  0 _params = IterUtil.skipLast(_params);
 2662    }
 2663   
 2664  0 @Override public boolean matches() { return false; }
 2665  0 @Override public boolean matchesWithBoxing() { return false; }
 2666   
 2667  0 @Override public boolean matchesWithVarargs() {
 2668  0 if (_varargParam instanceof VarargArrayType) {
 2669  0 boxArgs();
 2670  0 if (super.matches()) {
 2671  0 _params = IterUtil.compose(_params, _varargParam);
 2672  0 ArrayType arrayT = (ArrayType) substitute(_varargParam, _tparams, _targs);
 2673  0 _args = IterUtil.compose(_args, makeArray(arrayT, EMPTY_EXPRESSION_ITERABLE));
 2674  0 return true;
 2675    }
 2676    }
 2677  0 return false;
 2678    }
 2679   
 2680    }
 2681   
 2682    // cannot be defined statically, because it relies on the definition of non-static methods
 2683    private class MultiVarargMatcher extends SimpleMatcher {
 2684   
 2685    private Type _varargParam;
 2686    private Iterable<Expression> _varargArgs;
 2687   
 2688    /** Assumes {@code 1 <= params.size() < args.size()} */
 2689  12 public MultiVarargMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2690    Iterable<? extends VariableType> tparams, Iterable<? extends Type> targs) {
 2691  12 super(params, args, tparams, targs);
 2692  12 _varargParam = IterUtil.last(_params);
 2693  12 _params = IterUtil.skipLast(_params);
 2694  12 Pair<? extends Iterable<Expression>, ? extends Iterable<Expression>> splitArgs =
 2695    IterUtil.split(_args, IterUtil.sizeOf(_params));
 2696  12 _args = splitArgs.first();
 2697  12 _varargArgs = splitArgs.second();
 2698    }
 2699   
 2700  12 @Override public boolean matches() { return false; }
 2701  12 @Override public boolean matchesWithBoxing() { return false; }
 2702   
 2703  12 @Override public boolean matchesWithVarargs() {
 2704  12 if (_varargParam instanceof VarargArrayType) {
 2705  8 boxArgs();
 2706  8 if (super.matches()) {
 2707  8 ArrayType arrayT = (ArrayType) substitute(_varargParam, _tparams, _targs);
 2708  8 Type elementT = arrayT.ofType();
 2709  8 Iterable<Expression> boxedVarargArgs = EMPTY_EXPRESSION_ITERABLE;
 2710  8 for (Expression arg : _varargArgs) {
 2711  20 Expression boxed = boxingConvert(arg, elementT);
 2712    // TODO: Allow unchecked conversion of raw types?
 2713  0 if (!isSubtype(NodeProperties.getType(boxed), elementT)) { return false; }
 2714  20 boxedVarargArgs = IterUtil.compose(boxedVarargArgs, boxed);
 2715    }
 2716  8 _params = IterUtil.compose(_params, _varargParam);
 2717  8 _args = IterUtil.compose(_args, makeArray(arrayT, boxedVarargArgs));
 2718  8 return true;
 2719    }
 2720    }
 2721  4 return false;
 2722    }
 2723   
 2724    }
 2725   
 2726    // cannot be defined statically, because it relies on the definition of non-static methods
 2727    private class MultiVarargInferenceMatcher extends InferenceMatcher {
 2728   
 2729    private Type _varargParam;
 2730    private Iterable<Expression> _varargArgs;
 2731   
 2732    /** Assumes {@code 1 <= params.size() < args.size()} */
 2733  0 public MultiVarargInferenceMatcher(Iterable<? extends Type> params, Iterable<? extends Expression> args,
 2734    Iterable<? extends VariableType> tparams,
 2735    Type returned, Option<Type> expected) {
 2736  0 super(params, args, tparams, returned, expected);
 2737  0 _varargParam = IterUtil.last(_params);
 2738  0 _params = IterUtil.skipLast(_params);
 2739  0 Pair<? extends Iterable<Expression>, ? extends Iterable<Expression>> splitArgs =
 2740    IterUtil.split(_args, IterUtil.sizeOf(_params));
 2741  0 _args = splitArgs.first();
 2742  0 _varargArgs = splitArgs.second();
 2743    }
 2744   
 2745  0 @Override public boolean matches() { return false; }
 2746  0 @Override public boolean matchesWithBoxing() { return false; }
 2747   
 2748  0 @Override public boolean matchesWithVarargs() {
 2749  0 if (_varargParam instanceof VarargArrayType) {
 2750  0 boxArgs();
 2751  0 ArrayType arrayT = (ArrayType) _varargParam;
 2752  0 final Type elementT = arrayT.ofType();
 2753  0 Lambda<Expression, Expression> makeBoxed = new Lambda<Expression, Expression>() {
 2754  0 public Expression value(Expression e) { return boxingConvert(e, elementT); }
 2755    };
 2756  0 Iterable<Expression> boxedVarargArgs = IterUtil.map(_varargArgs, makeBoxed);
 2757  0 Iterable<Expression> inferenceArgs = IterUtil.compose(_args, boxedVarargArgs);
 2758  0 Iterable<Type> argTypes = IterUtil.mapSnapshot(inferenceArgs, NodeProperties.NODE_TYPE);
 2759  0 Iterable<Type> varargParams = IterUtil.copy(elementT, IterUtil.sizeOf(_varargArgs));
 2760  0 Iterable<Type> paramTypes = IterUtil.compose(_params, varargParams);
 2761  0 _targs = inferTypeArguments(_tparams, paramTypes, _returned, argTypes, _expected);
 2762  0 if (_targs != null) {
 2763  0 _params = IterUtil.compose(_params, _varargParam);
 2764  0 Expression newArg = makeArray((ArrayType) substitute(arrayT, _tparams, _targs), boxedVarargArgs);
 2765  0 _args = IterUtil.compose(_args, newArg);
 2766  0 return true;
 2767    }
 2768    }
 2769  0 return false;
 2770    }
 2771   
 2772    }
 2773   
 2774    }