Clover coverage report - DynamicJava Test Coverage (dynamicjava-20130518-r5436)
Coverage timestamp: Sat May 18 2013 03:01:28 CDT
file stats: LOC: 1,133   Methods: 187
NCLOC: 919   Classes: 9
 
 Source file Conditionals Statements Methods TOTAL
JLSTypeSystem.java 0% 0% 0% 0%
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.Triple;
 7    import edu.rice.cs.plt.tuple.Option;
 8    import edu.rice.cs.plt.tuple.Wrapper;
 9    import edu.rice.cs.plt.recur.*;
 10    import edu.rice.cs.plt.lambda.*;
 11    import edu.rice.cs.plt.iter.IterUtil;
 12    import edu.rice.cs.plt.collect.CollectUtil;
 13    import edu.rice.cs.plt.collect.IndexedRelation;
 14    import edu.rice.cs.plt.collect.Order;
 15    import edu.rice.cs.plt.collect.PredicateSet;
 16    import edu.rice.cs.plt.collect.Relation;
 17   
 18    import edu.rice.cs.dynamicjava.Options;
 19    import edu.rice.cs.dynamicjava.symbol.type.*;
 20   
 21    import static edu.rice.cs.plt.iter.IterUtil.mapSnapshot;
 22    import static edu.rice.cs.plt.iter.IterUtil.sizeOf;
 23    import static edu.rice.cs.plt.iter.IterUtil.zip;
 24    import static edu.rice.cs.plt.iter.IterUtil.filter;
 25    import static edu.rice.cs.plt.collect.CollectUtil.minList;
 26    import static edu.rice.cs.plt.collect.CollectUtil.union;
 27    import static edu.rice.cs.plt.collect.CollectUtil.asPredicateSet;
 28    import static edu.rice.cs.plt.collect.CollectUtil.asLambdaMap;
 29    import static edu.rice.cs.plt.lambda.LambdaUtil.bindFirst;
 30    import static edu.rice.cs.plt.lambda.LambdaUtil.bindSecond;
 31    import static edu.rice.cs.plt.lambda.LambdaUtil.asRunnable;
 32    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 33   
 34    public class JLSTypeSystem extends StandardTypeSystem {
 35   
 36    /**
 37    * Whether the inference algorithm and "join" should attempt to pack capture variables.
 38    * JLS does not specify this, but javac and Eclipse both do it.
 39    */
 40    private final boolean _packCaptureVars;
 41    /**
 42    * Whether the inference algorithm should use constraints inferred from arguments in all cases.
 43    * JLS is unclear, but the most straightforward interpretation is for this to be false. javac uses true (?
 44    * I initially thought it used false, for some reason); Eclipse uses true.
 45    */
 46    private final boolean _alwaysUseArgumentConstraints;
 47    /**
 48    * Whether the inference algorithm should only use declared parameter bounds as a last option (where
 49    * arguments and return type produce nothing). JLS does not do this, but javac does.
 50    */
 51    private final boolean _waitToUseDeclaredBounds;
 52   
 53  0 public JLSTypeSystem(Options opt) { this(opt, true, true, true, true, true, true); }
 54   
 55  0 public JLSTypeSystem(Options opt, boolean packCaptureVars, boolean alwaysUseArgumentConstraints,
 56    boolean waitToUseDeclaredBounds, boolean boxingInMostSpecific,
 57    boolean useExplicitTypeArgs, boolean strictClassEquality) {
 58  0 super(opt, boxingInMostSpecific, useExplicitTypeArgs, strictClassEquality);
 59  0 _packCaptureVars = packCaptureVars;
 60  0 _alwaysUseArgumentConstraints = alwaysUseArgumentConstraints;
 61  0 _waitToUseDeclaredBounds = waitToUseDeclaredBounds;
 62    }
 63   
 64    /** Determine if the type is well-formed. */
 65  0 public boolean isWellFormed(Type t) { return t.apply(new WellFormedTester()); }
 66   
 67    private class WellFormedTester extends TypeAbstractVisitor<Boolean> implements Predicate<Type> {
 68    final RecursionStack<Type> _stack = new RecursionStack<Type>(Wrapper.<Type>factory());
 69    Set<Wildcard> _visibleWildcards = new HashSet<Wildcard>();
 70   
 71  0 private Set<Wildcard> resetVisibleWildcards() {
 72  0 Set<Wildcard> result = _visibleWildcards;
 73  0 _visibleWildcards = new HashSet<Wildcard>();
 74  0 return result;
 75    }
 76   
 77  0 public boolean contains(Type t) { return t.apply(this); }
 78   
 79  0 @Override public Boolean defaultCase(Type t) { return true; }
 80   
 81  0 @Override public Boolean forArrayType(ArrayType t) { return t.ofType().apply(this); }
 82   
 83  0 @Override public Boolean forSimpleClassType(SimpleClassType t) {
 84  0 return IterUtil.isEmpty(SymbolUtil.allTypeParameters(t.ofClass()));
 85    }
 86   
 87  0 @Override public Boolean forRawClassType(RawClassType t) {
 88  0 return !IterUtil.isEmpty(SymbolUtil.allTypeParameters(t.ofClass()));
 89    }
 90   
 91  0 @Override public Boolean forParameterizedClassType(ParameterizedClassType t) {
 92  0 Iterable<? extends Type> args = t.typeArguments();
 93  0 boolean validArgs = true;
 94  0 for (Type arg : args) {
 95  0 validArgs &= arg.apply(new TypeAbstractVisitor<Boolean>() {
 96  0 @Override public Boolean defaultCase(Type t) {
 97  0 Set<Wildcard> old = resetVisibleWildcards();
 98  0 try { return t.apply(WellFormedTester.this); }
 99  0 finally { _visibleWildcards = old; }
 100    }
 101  0 @Override public Boolean forWildcard(Wildcard w) { return w.apply(WellFormedTester.this); }
 102    });
 103  0 if (!validArgs) { return false; }
 104    }
 105    // validArgs is true
 106  0 Iterable<VariableType> params = SymbolUtil.allTypeParameters(t.ofClass());
 107  0 if (sizeOf(params) == sizeOf(args)) {
 108  0 Iterable<Type> captArgs = captureTypeArgs(args, params);
 109  0 for (Pair<Type, Type> pair : zip(args, captArgs)) {
 110  0 if (pair.first() != pair.second()) {
 111    // must be a capture variable, so should be a VariableType
 112    // We can assume the bounds are well-formed -- otherwise, the redundant well-formed check
 113    // may require a further capture, and never terminate (this implies the relevant class
 114    // declaration is assumed to be well-formed).
 115    // We can also assume that containsVar(lower, cvar) is false.
 116  0 VariableType cvar = (VariableType) pair.second();
 117  0 Type lower = cvar.symbol().lowerBound();
 118  0 Type upper = cvar.symbol().upperBound();
 119  0 if (!isSubtype(lower, upper)) { return false; }
 120    }
 121    }
 122  0 return inBounds(params, captArgs);
 123    }
 124  0 else { return false; }
 125    }
 126   
 127  0 @Override public Boolean forIntersectionType(IntersectionType t) {
 128  0 return IterUtil.and(t.ofTypes(), this);
 129    }
 130   
 131  0 @Override public Boolean forUnionType(UnionType t) { return false; }
 132   
 133  0 @Override public Boolean forVariableType(final VariableType t) {
 134  0 Set<Wildcard> old = resetVisibleWildcards();
 135  0 try {
 136  0 Thunk<Boolean> recur = new Thunk<Boolean>() {
 137  0 public Boolean value() {
 138  0 Type lower = t.symbol().lowerBound();
 139  0 Type upper = t.symbol().upperBound();
 140  0 return lower.apply(WellFormedTester.this) && upper.apply(WellFormedTester.this) &&
 141    isSubtype(lower, upper) && !containsVar(lower, t);
 142    }
 143    };
 144    // assume it's well-formed if we're already checking it
 145  0 return _stack.apply(recur, true, t);
 146    }
 147  0 finally { _visibleWildcards = old; }
 148    }
 149   
 150  0 @Override public Boolean forWildcard(final Wildcard w) {
 151  0 if (_visibleWildcards.contains(w)) { return true; }
 152    else {
 153  0 Thunk<Boolean> recur = new Thunk<Boolean>() {
 154  0 public Boolean value() {
 155  0 Type lower = w.symbol().lowerBound();
 156  0 Type upper = w.symbol().upperBound();
 157  0 _visibleWildcards.add(w);
 158  0 try {
 159  0 if (upper.apply(WellFormedTester.this)) {
 160  0 Set<Wildcard> old = resetVisibleWildcards();
 161  0 try { return lower.apply(WellFormedTester.this) && isSubtype(lower, upper); }
 162  0 finally { _visibleWildcards = old; }
 163    }
 164  0 else { return false; }
 165    }
 166  0 finally { _visibleWildcards.remove(w); }
 167    }
 168    };
 169    // if we encounter a wildcard we've seen before that isn't visible, it's malformed
 170  0 return _stack.apply(recur, false, w);
 171    }
 172    }
 173    }
 174   
 175   
 176    /** Determine if the given types may be treated as equal. This is recursive, transitive, and symmetric. */
 177  0 public boolean isEqual(Type t1, Type t2) {
 178  0 return new IsEqualTester().contains(t1, t2);
 179    }
 180   
 181    private class IsEqualTester implements Order<Type>, Lambda2<Type, Type, Boolean> {
 182    RecursionStack2<Type, Type> _stack = new RecursionStack2<Type, Type>(Pair.<Type, Type>factory());
 183   
 184  0 public Boolean value(Type subT, Type superT) { return contains(subT, superT); }
 185   
 186  0 public boolean contains(final Type t1, final Type t2) {
 187  0 return t1.apply(new TypeAbstractVisitor<Boolean>() {
 188  0 @Override public Boolean defaultCase(Type t1) { return t1.equals(t2); }
 189   
 190  0 @Override public Boolean forArrayType(ArrayType t1) {
 191  0 return (t2 instanceof ArrayType) && contains(t1.ofType(), ((ArrayType) t2).ofType());
 192    }
 193   
 194  0 @Override public Boolean forSimpleClassType(SimpleClassType t1) {
 195  0 return (t2 instanceof SimpleClassType) && sameClass(t1, (ClassType) t2);
 196    }
 197   
 198  0 @Override public Boolean forRawClassType(RawClassType t1) {
 199  0 return (t2 instanceof RawClassType) && sameClass(t1, (ClassType) t2);
 200    }
 201   
 202  0 @Override public Boolean forParameterizedClassType(ParameterizedClassType t1) {
 203  0 if (t2 instanceof ParameterizedClassType) {
 204  0 ParameterizedClassType t2Cast = (ParameterizedClassType) t2;
 205  0 if (sameClass(t1, t2Cast)) {
 206  0 if (sizeOf(t1.typeArguments()) == sizeOf(t2Cast.typeArguments())) {
 207  0 return IterUtil.and(t1.typeArguments(), t2Cast.typeArguments(), IsEqualTester.this);
 208    }
 209    }
 210    }
 211  0 return false;
 212    }
 213   
 214  0 @Override public Boolean forIntersectionType(IntersectionType t1) {
 215  0 return t2 instanceof IntersectionType &&
 216    IterUtil.and(t1.ofTypes(), ((IntersectionType) t2).ofTypes(), IsEqualTester.this);
 217    }
 218   
 219  0 @Override public Boolean forWildcard(final Wildcard t1) {
 220  0 if (t2 instanceof Wildcard) {
 221  0 Thunk<Boolean> recur = new Thunk<Boolean>() {
 222  0 public Boolean value() {
 223  0 BoundedSymbol s1 = t1.symbol();
 224  0 BoundedSymbol s2 = ((Wildcard) t2).symbol();
 225  0 return IsEqualTester.this.contains(s1.upperBound(), s2.upperBound()) &&
 226    IsEqualTester.this.contains(s1.lowerBound(), s2.lowerBound());
 227    }
 228    };
 229  0 return _stack.apply(recur, true, t1, t2);
 230    }
 231  0 else { return false; }
 232    }
 233   
 234    });
 235    }
 236    }
 237   
 238    /**
 239    * Determine if {@code subT} is a subtype of {@code superT}. This is a recursive
 240    * (in terms of {@link #isEqual}), transitive relation.
 241    */
 242  0 public boolean isSubtype(Type subT, Type superT) { return new Subtyper().contains(subT, superT); }
 243   
 244    /**
 245    * Tests subtyping. Due to its use of internal state, unrelated (and possibly parallel)
 246    * invocations should use distinct instances.
 247    */
 248    private class Subtyper implements Order<Type>, Lambda2<Type, Type, Boolean> {
 249    RecursionStack2<Type, Type> _stack = new RecursionStack2<Type, Type>(Pair.<Type, Type>factory());
 250   
 251  0 public Boolean value(Type subT, Type superT) { return contains(subT, superT); }
 252   
 253  0 public Predicate<Type> supertypes(Type sub) { return bindFirst((Order<Type>) this, sub); }
 254   
 255  0 public Predicate<Type> subtypes(Type sup) { return bindSecond((Order<Type>) this, sup); }
 256   
 257  0 public boolean contains(final Type subT, final Type superT) {
 258  0 debug.logStart(new String[]{"subT", "superT"}, wrap(subT), wrap(superT)); try {
 259   
 260  0 if (subT.equals(superT)) { return true; } // what follows assumes the types are not syntactically equal
 261   
 262    // Handle easy superT cases; return null if subT cases need to be considered, too
 263  0 Boolean result = superT.apply(new TypeAbstractVisitor<Boolean>() {
 264  0 public Boolean defaultCase(Type superT) { return null; }
 265   
 266  0 @Override public Boolean forVariableType(final VariableType superT) {
 267  0 return subT.apply(new TypeAbstractVisitor<Boolean>() {
 268  0 public Boolean defaultCase(final Type subT) {
 269  0 Thunk<Boolean> checkLowerBound = new Thunk<Boolean>() {
 270  0 public Boolean value() {
 271  0 return Subtyper.this.contains(subT, superT.symbol().lowerBound());
 272    }
 273    };
 274  0 Thunk<Boolean> checkInfinite = new Thunk<Boolean>() {
 275  0 public Boolean value() { return Subtyper.this.contains(subT, NULL); }
 276    };
 277  0 return _stack.apply(checkLowerBound, checkInfinite, subT, superT);
 278    }
 279  0 @Override public Boolean forVariableType(VariableType subT) {
 280  0 return defaultCase(subT) ? true : null;
 281    }
 282  0 @Override public Boolean forIntersectionType(IntersectionType subT) {
 283  0 return defaultCase(subT) ? true : null;
 284    }
 285  0 @Override public Boolean forBottomType(BottomType subT) { return true; }
 286    });
 287    }
 288   
 289  0 @Override public Boolean forIntersectionType(IntersectionType superT) {
 290  0 if (subT instanceof BottomType) { return true; }
 291  0 else { return IterUtil.and(superT.ofTypes(), supertypes(subT)); }
 292    }
 293   
 294  0 @Override public Boolean forTopType(TopType superT) { return true; }
 295    });
 296   
 297  0 if (result != null) { return result; }
 298   
 299    // Handle subT-based cases:
 300  0 return subT.apply(new TypeAbstractVisitor<Boolean>() {
 301   
 302  0 public Boolean defaultCase(Type t) { return false; }
 303   
 304  0 public Boolean forCharType(CharType subT) {
 305  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 306  0 public Boolean defaultCase(Type superT) { return false; }
 307  0 @Override public Boolean forCharType(CharType superT) { return true; }
 308  0 @Override public Boolean forIntType(IntType superT) { return true; }
 309  0 @Override public Boolean forLongType(LongType superT) { return true; }
 310  0 @Override public Boolean forFloatingPointType(FloatingPointType superT) { return true; }
 311    });
 312    }
 313   
 314  0 public Boolean forByteType(ByteType subT) {
 315  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 316  0 public Boolean defaultCase(Type superT) { return false; }
 317  0 @Override public Boolean forIntegerType(IntegerType superT) { return true; }
 318  0 @Override public Boolean forFloatingPointType(FloatingPointType superT) { return true; }
 319    });
 320    }
 321   
 322  0 public Boolean forShortType(ShortType subT) {
 323  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 324  0 public Boolean defaultCase(Type superT) { return false; }
 325  0 @Override public Boolean forShortType(ShortType superT) { return true; }
 326  0 @Override public Boolean forIntType(IntType superT) { return true; }
 327  0 @Override public Boolean forLongType(LongType superT) { return true; }
 328  0 @Override public Boolean forFloatingPointType(FloatingPointType superT) { return true; }
 329    });
 330    }
 331   
 332  0 public Boolean forIntType(IntType subT) {
 333  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 334  0 public Boolean defaultCase(Type superT) { return false; }
 335  0 @Override public Boolean forIntType(IntType superT) { return true; }
 336  0 @Override public Boolean forLongType(LongType superT) { return true; }
 337  0 @Override public Boolean forFloatingPointType(FloatingPointType superT) { return true; }
 338    });
 339    }
 340   
 341  0 public Boolean forLongType(LongType subT) {
 342  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 343  0 public Boolean defaultCase(Type superT) { return false; }
 344  0 @Override public Boolean forLongType(LongType superT) { return true; }
 345  0 @Override public Boolean forFloatingPointType(FloatingPointType superT) { return true; }
 346    });
 347    }
 348   
 349  0 public Boolean forFloatType(FloatType subT) { return superT instanceof FloatingPointType; }
 350   
 351  0 public Boolean forNullType(NullType subT) { return isReference(superT); }
 352   
 353  0 public Boolean forSimpleArrayType(SimpleArrayType subT) { return handleArrayType(subT); }
 354   
 355  0 public Boolean forVarargArrayType(VarargArrayType subT) { return handleArrayType(subT); }
 356   
 357  0 private Boolean handleArrayType(final ArrayType subT) {
 358  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 359  0 public Boolean defaultCase(Type superT) { return false; }
 360   
 361  0 @Override public Boolean forArrayType(ArrayType superT) {
 362  0 if (isPrimitive(subT.ofType())) {
 363    // types may be inequal if one is vararg and the other is not
 364  0 return subT.ofType().equals(superT.ofType());
 365    }
 366  0 else { return Subtyper.this.contains(subT.ofType(), superT.ofType()); }
 367    }
 368   
 369  0 @Override public Boolean forClassType(ClassType superT) {
 370  0 return Subtyper.this.contains(CLONEABLE_AND_SERIALIZABLE, superT);
 371    }
 372   
 373    });
 374    }
 375   
 376  0 @Override public Boolean forSimpleClassType(final SimpleClassType subT) {
 377  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 378  0 @Override public Boolean defaultCase(Type superT) { return false; }
 379  0 @Override public Boolean forClassType(ClassType superT) {
 380  0 Type newSub = immediateSupertype(subT);
 381  0 if (newSub == null) { return false; }
 382  0 else { return Subtyper.this.contains(newSub, superT); }
 383    }
 384  0 @Override public Boolean forSimpleClassType(SimpleClassType superT) {
 385  0 return sameClass(subT, superT) || forClassType(superT);
 386    }
 387    });
 388    }
 389   
 390  0 @Override public Boolean forRawClassType(final RawClassType subT) {
 391  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 392  0 @Override public Boolean defaultCase(Type superT) { return false; }
 393  0 @Override public Boolean forClassType(final ClassType superT) {
 394  0 Type newSub = immediateSupertype(subT);
 395  0 if (newSub == null) { return false; }
 396  0 else { return Subtyper.this.contains(newSub, superT); }
 397    }
 398  0 @Override public Boolean forRawClassType(final RawClassType superT) {
 399  0 return sameClass(subT, superT) || forClassType(superT);
 400    }
 401  0 @Override public Boolean forParameterizedClassType(final ParameterizedClassType superT) {
 402  0 if (sameClass(subT, superT)) {
 403  0 return Subtyper.this.contains(parameterize(subT), superT) || forClassType(superT);
 404    }
 405  0 else { return forClassType(superT); }
 406    }
 407    });
 408    }
 409   
 410  0 public Boolean forParameterizedClassType(final ParameterizedClassType subT) {
 411  0 return superT.apply(new TypeAbstractVisitor<Boolean>() {
 412  0 @Override public Boolean defaultCase(Type superT) { return false; }
 413   
 414  0 @Override public Boolean forClassType(ClassType superT) {
 415  0 Type newSub = immediateSupertype(subT);
 416  0 if (newSub == null) { return false; }
 417  0 else { return Subtyper.this.contains(newSub, superT); }
 418    }
 419   
 420  0 @Override public Boolean forParameterizedClassType(final ParameterizedClassType superT) {
 421  0 if (sameClass(subT, superT)) {
 422  0 boolean result = true;
 423  0 ParameterizedClassType subCapT = capture(subT);
 424  0 for (final Triple<Type, Type, Type> args : zip(subT.typeArguments(),
 425    subCapT.typeArguments(),
 426    superT.typeArguments())) {
 427  0 result &= args.third().apply(new TypeAbstractVisitor<Boolean>() {
 428  0 public Boolean defaultCase(Type superArg) {
 429  0 return isEqual(args.second(), superArg);
 430    }
 431  0 @Override public Boolean forWildcard(final Wildcard superArg) {
 432  0 Thunk<Boolean> inBounds = new Thunk<Boolean>() {
 433  0 public Boolean value() {
 434  0 Type subArg = args.second();
 435  0 return Subtyper.this.contains(superArg.symbol().lowerBound(), subArg) &&
 436    Subtyper.this.contains(subArg, superArg.symbol().upperBound());
 437    }
 438    };
 439    // if we've seen this sub arg/super arg combo before, we can prove subtyping inductively
 440    // (assuming superArg appears in a valid context -- checked by isWellFormed)
 441    // Put the pre-capture sub arg on the stack, because post-capture it may be a fresh var
 442  0 return _stack.apply(inBounds, true, args.first(), superArg);
 443    }
 444    });
 445  0 if (!result) { break; }
 446    }
 447  0 return result || forClassType(superT);
 448    }
 449  0 else { return forClassType(superT); }
 450    }
 451   
 452  0 @Override public Boolean forRawClassType(RawClassType superT) {
 453  0 if (sameClass(subT, superT)) {
 454  0 return Subtyper.this.contains(erase(subT), superT);
 455    }
 456  0 else { return forClassType(superT); }
 457    }
 458   
 459    });
 460    }
 461   
 462  0 public Boolean forVariableType(final VariableType subT) {
 463  0 Thunk<Boolean> checkUpperBound = new Thunk<Boolean>() {
 464  0 public Boolean value() {
 465  0 return Subtyper.this.contains(subT.symbol().upperBound(), superT);
 466    }
 467    };
 468  0 Thunk<Boolean> checkInfinite = new Thunk<Boolean>() {
 469  0 public Boolean value() { return Subtyper.this.contains(OBJECT, superT); }
 470    };
 471  0 return _stack.apply(checkUpperBound, checkInfinite, subT, superT);
 472    }
 473   
 474  0 public Boolean forIntersectionType(IntersectionType subT) {
 475  0 return IterUtil.or(subT.ofTypes(), subtypes(superT));
 476    }
 477   
 478  0 public Boolean forBottomType(BottomType subT) { return true; }
 479    });
 480  0 } finally { debug.logEnd(); }
 481    }
 482    };
 483   
 484   
 485    /** Join implementation based on the JLS specification (15.12.2.7). */
 486  0 public Type join(Iterable<? extends Type> ts) {
 487  0 return join(ts, new PrecomputedRecursionStack<Set<Type>, Wildcard>(Wrapper.<Set<Type>>factory()));
 488    }
 489   
 490  0 private Type join(Iterable<? extends Type> ts, final PrecomputedRecursionStack<Set<Type>, Wildcard> joinStack) {
 491  0 if (_packCaptureVars) {
 492  0 ts = IterUtil.mapSnapshot(ts, new Lambda<Type, Type>() {
 493  0 public Type value(Type t) {
 494  0 while (t instanceof VariableType && ((VariableType) t).symbol().generated()) {
 495  0 t = ((VariableType) t).symbol().upperBound();
 496    }
 497  0 return t;
 498    }
 499    });
 500    }
 501  0 switch (sizeOf(ts, 2)) {
 502  0 case 0: return BOTTOM;
 503  0 case 1: return IterUtil.first(ts);
 504  0 default:
 505  0 boolean hasNonReference = false;
 506  0 boolean hasReference = false;
 507  0 for (Type t : ts) {
 508  0 if (isReference(t)) { hasReference = true; }
 509  0 else { hasNonReference = true; }
 510    }
 511  0 if (hasNonReference && hasReference) { return TOP; }
 512    else {
 513  0 final Set<Type> toJoin = CollectUtil.asSet(filter(ts, bindFirst(LambdaUtil.NOT_EQUAL, NULL)));
 514  0 switch (toJoin.size()) {
 515  0 case 0: return NULL;
 516  0 case 1: return IterUtil.first(toJoin);
 517  0 default:
 518  0 Set<Type> erasedTypes = IterUtil.first(toJoin).apply(new ErasedSuperAccumulator()).result();
 519  0 for (Type t : IterUtil.skipFirst(toJoin)) {
 520  0 erasedTypes.retainAll(t.apply(new ErasedSuperAccumulator()).result());
 521    }
 522  0 List<Type> minimalSupers = minList(erasedTypes, new Subtyper());
 523  0 Iterable<Type> conjuncts = mapSnapshot(minimalSupers, new Lambda<Type, Type>() {
 524  0 public Type value(Type erasedT) {
 525  0 if (erasedT instanceof RawClassType) {
 526  0 TypeArgumentMerger merger = new TypeArgumentMerger((RawClassType) erasedT);
 527  0 IterUtil.run(toJoin, asRunnable(merger));
 528  0 return merger.result(joinStack);
 529    }
 530  0 else { return erasedT; }
 531    }
 532    });
 533  0 return meet(conjuncts);
 534    }
 535    }
 536    }
 537    }
 538   
 539    /** Accumulates a set (ordered depth-first) of erased supertypes of the given type. */
 540    private class ErasedSuperAccumulator extends TypeAbstractVisitor<ErasedSuperAccumulator> {
 541    private final Set<Type> _result;
 542    private final RecursionStack<Type> _stack;
 543   
 544  0 public ErasedSuperAccumulator() {
 545  0 _result = new LinkedHashSet<Type>();
 546  0 _stack = new RecursionStack<Type>(Wrapper.<Type>factory());
 547    }
 548   
 549  0 public Set<Type> result() { return _result; }
 550   
 551  0 @Override public ErasedSuperAccumulator forPrimitiveType(PrimitiveType t) {
 552  0 _result.add(t);
 553  0 return this;
 554    }
 555   
 556  0 @Override public ErasedSuperAccumulator forCharType(CharType t) {
 557  0 _result.addAll(Arrays.asList(CHAR, INT, LONG, FLOAT, DOUBLE));
 558  0 return this;
 559    }
 560   
 561  0 @Override public ErasedSuperAccumulator forByteType(ByteType t) {
 562  0 _result.addAll(Arrays.asList(BYTE, SHORT, INT, LONG, FLOAT, DOUBLE));
 563  0 return this;
 564    }
 565   
 566  0 @Override public ErasedSuperAccumulator forShortType(ShortType t) {
 567  0 _result.addAll(Arrays.asList(SHORT, INT, LONG, FLOAT, DOUBLE));
 568  0 return this;
 569    }
 570   
 571  0 @Override public ErasedSuperAccumulator forIntType(IntType t) {
 572  0 _result.addAll(Arrays.asList(INT, LONG, FLOAT, DOUBLE));
 573  0 return this;
 574    }
 575   
 576  0 @Override public ErasedSuperAccumulator forLongType(LongType t) {
 577  0 _result.addAll(Arrays.asList(LONG, FLOAT, DOUBLE));
 578  0 return this;
 579    }
 580   
 581  0 @Override public ErasedSuperAccumulator forFloatType(FloatType t) {
 582  0 _result.addAll(Arrays.asList(FLOAT, DOUBLE));
 583  0 return this;
 584    }
 585   
 586  0 @Override public ErasedSuperAccumulator forNullType(NullType t) {
 587  0 _result.add(t);
 588  0 return this;
 589    }
 590   
 591  0 @Override public ErasedSuperAccumulator forArrayType(ArrayType t) {
 592  0 Set<Type> elementTypes = t.ofType().apply(new ErasedSuperAccumulator()).result();
 593  0 for (Type elt : elementTypes) {
 594  0 _result.add(new SimpleArrayType(elt));
 595    }
 596  0 CLONEABLE_AND_SERIALIZABLE.apply(this);
 597  0 return this;
 598    }
 599   
 600  0 @Override public ErasedSuperAccumulator forClassType(ClassType t) {
 601  0 _result.add(erase(t));
 602  0 Type sup = immediateSupertype(t);
 603  0 if (sup != null) { sup.apply(this); }
 604  0 return this;
 605    }
 606   
 607  0 @Override public ErasedSuperAccumulator forIntersectionType(IntersectionType t) {
 608  0 for (Type sup : t.ofTypes()) { sup.apply(this); }
 609  0 return this;
 610    }
 611   
 612  0 @Override public ErasedSuperAccumulator forVariableType(final VariableType t) {
 613  0 Runnable recurOnBound = asRunnable(bindFirst(this, t.symbol().upperBound()));
 614  0 Runnable recurOnObject = asRunnable(bindFirst(this, OBJECT));
 615  0 _stack.run(recurOnBound, recurOnObject, t);
 616  0 return this;
 617    }
 618   
 619    }
 620   
 621    /**
 622    * Finds an instantiation of a raw class type that is a supertype of the visited types.
 623    * Visiting types that are not subtypes of the raw class has no effect on the result.
 624    */
 625    private class TypeArgumentMerger extends TypeAbstractVisitor<TypeArgumentMerger> {
 626    private final DJClass _c;
 627    private final RecursionStack<Type> _stack;
 628    private final List<ArgSet> _args;
 629    private boolean _rawResult; // whether the result should be a raw type
 630   
 631  0 public TypeArgumentMerger(RawClassType erased) {
 632  0 _c = erased.ofClass();
 633  0 _stack = new RecursionStack<Type>(Wrapper.<Type>factory());
 634  0 int params = sizeOf(SymbolUtil.allTypeParameters(_c));
 635  0 _args = new ArrayList<ArgSet>(params);
 636  0 for (int i = 0; i < params; i++) { _args.add(new ArgSet()); }
 637  0 _rawResult = false;
 638    }
 639   
 640  0 public ClassType result(final PrecomputedRecursionStack<Set<Type>, Wildcard> joinStack) {
 641  0 if (_rawResult) { return new RawClassType(_c); }
 642    else {
 643  0 return new ParameterizedClassType(_c, mapSnapshot(_args, new Lambda<ArgSet, Type>() {
 644  0 public Type value(ArgSet set) { return set.merge(joinStack); }
 645    }));
 646    }
 647    }
 648   
 649  0 @Override public TypeArgumentMerger defaultCase(Type t) { return this; } // ignore by default
 650   
 651  0 @Override public TypeArgumentMerger forArrayType(ArrayType t) {
 652  0 return CLONEABLE_AND_SERIALIZABLE.apply(this);
 653    }
 654   
 655  0 @Override public TypeArgumentMerger forClassType(ClassType t) {
 656  0 Type sup = immediateSupertype(t);
 657  0 if (sup != null) { sup.apply(this); }
 658  0 return this;
 659    }
 660   
 661  0 @Override public TypeArgumentMerger forRawClassType(RawClassType t) {
 662  0 if (t.ofClass().equals(_c)) { _rawResult = true; }
 663  0 else { forClassType(t); }
 664  0 return this;
 665    }
 666   
 667  0 @Override public TypeArgumentMerger forParameterizedClassType(ParameterizedClassType t) {
 668  0 if (t.ofClass().equals(_c)) {
 669  0 for (Pair<ArgSet, Type> p : zip(_args, t.typeArguments())) { p.first().add(p.second()); }
 670    }
 671  0 else { forClassType(t); }
 672  0 return this;
 673    }
 674   
 675  0 @Override public TypeArgumentMerger forIntersectionType(IntersectionType t) {
 676    // Only of the elements needs to be an instantiation of _c, but since we don't know
 677    // which one (and get no feedback), we'll just do them all. If we have multiple-instantiation
 678    // inheritance (prohibited by JLS), we'll merge the arguments from all of them, but that's okay.
 679  0 for (Type sup : t.ofTypes()) { sup.apply(this); }
 680  0 return this;
 681    }
 682   
 683  0 @Override public TypeArgumentMerger forVariableType(VariableType t) {
 684  0 Runnable recurOnBound = asRunnable(bindFirst(this, t.symbol().upperBound()));
 685  0 Runnable recurOnObject = asRunnable(bindFirst(this, OBJECT));
 686  0 _stack.run(recurOnBound, recurOnObject, t);
 687  0 return this;
 688    }
 689   
 690    private class ArgSet {
 691    private final Set<Type> _types;
 692    private boolean _wildcardUpper;
 693    private boolean _wildcardLower;
 694   
 695  0 public ArgSet() {
 696  0 _types = new LinkedHashSet<Type>();
 697  0 _wildcardUpper = false;
 698  0 _wildcardLower = false;
 699    }
 700   
 701  0 public void add(Type t) {
 702  0 if (t instanceof Wildcard) {
 703  0 BoundedSymbol s = ((Wildcard) t).symbol();
 704  0 if (s.upperBound().equals(OBJECT)) {
 705  0 if (s.lowerBound().equals(NULL)) { _wildcardUpper = true; }
 706  0 else { _types.add(s.lowerBound()); _wildcardLower = true; }
 707    }
 708  0 else { _types.add(s.upperBound()); _wildcardUpper = true; }
 709    }
 710  0 else { _types.add(t); }
 711    }
 712   
 713  0 public Type merge(final PrecomputedRecursionStack<Set<Type>, Wildcard> joinStack) {
 714  0 if (_types.isEmpty() || (_wildcardUpper && _wildcardLower)) {
 715  0 return new Wildcard(new BoundedSymbol(new Object(), OBJECT, NULL));
 716    }
 717  0 else if (_wildcardLower) {
 718  0 return new Wildcard(new BoundedSymbol(new Object(), OBJECT, meet(_types)));
 719    }
 720  0 else if (_wildcardUpper || _types.size() > 1) {
 721  0 final Wildcard result = new Wildcard(new BoundedSymbol(new Object()));
 722  0 Thunk<Wildcard> recur = new Thunk<Wildcard>() {
 723  0 public Wildcard value() {
 724  0 result.symbol().initializeLowerBound(NULL);
 725  0 result.symbol().initializeUpperBound(join(_types, joinStack));
 726  0 return result;
 727    }
 728    };
 729  0 return joinStack.apply(recur, result, _types);
 730    }
 731    else { // no wildcards, size is 1
 732  0 return IterUtil.first(_types);
 733    }
 734    }
 735   
 736    }
 737    }
 738   
 739   
 740    /** Simple meet implementation: construct an intersection if there are more than two. */
 741  0 public Type meet(Iterable<? extends Type> ts) {
 742  0 Set<? extends Type> toMeet = CollectUtil.asSet(ts);
 743  0 switch (toMeet.size()) {
 744  0 case 0: return TOP;
 745  0 case 1: return IterUtil.first(toMeet);
 746  0 default: return new IntersectionType(IterUtil.snapshot(toMeet));
 747    }
 748    }
 749   
 750  0 protected Iterable<Type> captureTypeArgs(Iterable<? extends Type> targs,
 751    Iterable<? extends VariableType> params) {
 752  0 List<BoundedSymbol> captureVars = new LinkedList<BoundedSymbol>();
 753  0 List<Type> newArgs = new LinkedList<Type>();
 754  0 for (Type arg : targs) {
 755  0 if (arg instanceof Wildcard) {
 756  0 BoundedSymbol s = new BoundedSymbol(new Object());
 757  0 captureVars.add(s);
 758  0 newArgs.add(new VariableType(s));
 759    }
 760  0 else { captureVars.add(null); newArgs.add(arg); }
 761    }
 762   
 763  0 final SubstitutionMap sigma = new SubstitutionMap(params, newArgs);
 764  0 Set<VariableType> remainingParams = new HashSet<VariableType>();
 765  0 CollectUtil.addAll(remainingParams, params);
 766  0 while (!remainingParams.isEmpty()) {
 767  0 boolean changed = false;
 768  0 for (Triple<BoundedSymbol, Type, VariableType> triple : zip(captureVars, targs, params)) {
 769  0 VariableType param = triple.third();
 770  0 if (!containsAnyVar(param.symbol().lowerBound(), remainingParams)) {
 771  0 Type arg = triple.second();
 772  0 if (arg instanceof Wildcard) {
 773  0 Wildcard argW = (Wildcard) arg;
 774  0 Type wildU = argW.symbol().upperBound();
 775  0 Type paramU = substitute(param.symbol().upperBound(), sigma);
 776  0 Type wildL = argW.symbol().lowerBound();
 777  0 Type paramL = substitute(param.symbol().lowerBound(), sigma);
 778   
 779  0 Type captU = wildU.equals(OBJECT) ? paramU :
 780  0 paramU.equals(OBJECT) ? wildU : new IntersectionType(IterUtil.make(wildU, paramU));
 781  0 triple.first().initializeUpperBound(captU);
 782  0 triple.first().initializeLowerBound(join(wildL, paramL));
 783    }
 784  0 remainingParams.remove(param);
 785  0 changed = true;
 786    }
 787    }
 788  0 if (!changed) { throw new IllegalArgumentException("Params have circular lower-bound dependency: " + params); }
 789    }
 790  0 return newArgs;
 791    }
 792   
 793   
 794    /**
 795    * Top-level entry point for type inference. Produces the set of types corresponding to the given
 796    * type parameters, given that {@code args} were provided where {@code params} were expected
 797    * ({@code args} and {@code params} are assumed to have the same length), and {@code returned} will
 798    * be returned where {@code expected} is expected.
 799    *
 800    * @return A set of inferred type arguments for {@code tparams}, or {@code null} if the parameters
 801    * are over-constrained
 802    */
 803  0 protected Iterable<Type> inferTypeArguments(Iterable<? extends VariableType> tparams,
 804    Iterable<? extends Type> params, Type returned,
 805    Iterable<? extends Type> args, Option<Type> expected) {
 806    //debug.logValues("Beginning inferTypeArguments",
 807    // new String[]{ "tparams", "params", "returned", "args", "expected" },
 808    // wrap(tparams), wrap(params), wrap(returned), wrap(args), wrap(expected));
 809  0 Inferencer inf = new Inferencer(CollectUtil.makeSet(tparams));
 810   
 811    // perform inference for args
 812  0 for (Pair<Type, Type> pair : zip(args, params)) {
 813  0 inf.subtype(pair.first(), pair.second());
 814    }
 815   
 816  0 ConstraintSet constraints = inf.constraints();
 817  0 Map<VariableType, Type> instantiations = new HashMap<VariableType, Type>();
 818  0 Iterable<VariableType> toInfer = filter(tparams, LambdaUtil.negate(asPredicateSet(instantiations.keySet())));
 819   
 820    // handle equal bounds
 821  0 for (VariableType var : toInfer) {
 822  0 Set<Type> eqBounds = constraints.equalBounds(var);
 823  0 if (!eqBounds.isEmpty()) { instantiations.put(var, IterUtil.first(eqBounds)); }
 824    }
 825   
 826    // handle lower bounds
 827  0 for (VariableType var : toInfer) {
 828  0 Set<Type> lowerBounds = constraints.lowerBounds(var);
 829  0 if (!lowerBounds.isEmpty()) { instantiations.put(var, join(lowerBounds)); }
 830    }
 831   
 832  0 if (!_alwaysUseArgumentConstraints) {
 833    // throw away inferred bounds from arguments
 834  0 inf = new Inferencer(CollectUtil.makeSet(toInfer));
 835  0 constraints = inf.constraints();
 836    }
 837   
 838    // perform inference for expected type
 839  0 if (expected.isSome()) {
 840  0 inf.supertype(expected.unwrap(), substitute(returned, new SubstitutionMap(instantiations)));
 841  0 for (VariableType var : toInfer) {
 842  0 Set<Type> eqBounds = constraints.equalBounds(var);
 843  0 if (!eqBounds.isEmpty()) { instantiations.put(var, IterUtil.first(eqBounds)); }
 844    }
 845    }
 846   
 847    // use upper bounds (may be inferred from args or expected, and may be declared)
 848  0 if (_waitToUseDeclaredBounds) {
 849  0 for (VariableType var : toInfer) {
 850  0 Set<Type> upperBounds = constraints.upperBounds(var);
 851  0 if (!upperBounds.isEmpty()) { instantiations.put(var, meet(upperBounds)); }
 852    }
 853  0 for (VariableType var : toInfer) {
 854  0 instantiations.put(var, substitute(var.symbol().upperBound(), new SubstitutionMap(instantiations)));
 855    }
 856    }
 857    else {
 858  0 for (VariableType var : toInfer) {
 859  0 Set<Type> upperBounds = constraints.upperBounds(var);
 860  0 Type declared = var.symbol().upperBound();
 861  0 if (!declared.equals(OBJECT)) {
 862  0 upperBounds = union(upperBounds, substitute(declared, new SubstitutionMap(instantiations)));
 863    }
 864  0 instantiations.put(var, meet(upperBounds));
 865    }
 866    }
 867   
 868  0 Iterable<Type> result = mapSnapshot(tparams, asLambdaMap(instantiations));
 869  0 SubstitutionMap sigma = new SubstitutionMap(tparams, result);
 870  0 boolean valid = inBounds(tparams, result);
 871  0 for (Pair<Type, Type> pair : zip(args, params)) {
 872  0 if (!valid) { break; }
 873  0 valid &= isSubtype(pair.first(), substitute(pair.second(), sigma));
 874    }
 875  0 return valid ? result : null;
 876    }
 877   
 878    private class ConstraintSet {
 879    private final Relation<VariableType, Type> _equalBounds;
 880    private final Relation<VariableType, Type> _upperBounds;
 881    private final Relation<VariableType, Type> _lowerBounds;
 882   
 883  0 public ConstraintSet() {
 884  0 Thunk<Map<VariableType, PredicateSet<Type>>> mapFactory = CollectUtil.hashMapFactory();
 885  0 Thunk<Set<Type>> setFactory = CollectUtil.linkedHashSetFactory();
 886  0 _equalBounds = new IndexedRelation<VariableType, Type>(mapFactory, setFactory);
 887  0 _upperBounds = new IndexedRelation<VariableType, Type>(mapFactory, setFactory);
 888  0 _lowerBounds = new IndexedRelation<VariableType, Type>(mapFactory, setFactory);
 889    }
 890   
 891  0 public void addEqualBound(VariableType var, Type t) { _equalBounds.add(var, t); }
 892  0 public void addUpperBound(VariableType var, Type t) {
 893  0 _upperBounds.add(var, t);
 894    }
 895  0 public void addLowerBound(VariableType var, Type t) {
 896  0 _lowerBounds.add(var, t);
 897    }
 898   
 899  0 public Set<Type> equalBounds(VariableType var) { return _equalBounds.matchFirst(var); }
 900  0 public Set<Type> upperBounds(VariableType var) { return _upperBounds.matchFirst(var); }
 901  0 public Set<Type> lowerBounds(VariableType var) { return _lowerBounds.matchFirst(var); }
 902    }
 903   
 904    private class Inferencer {
 905    private final Set<? extends VariableType> _vars;
 906    private final ConstraintSet _constraints;
 907    private final RecursionStack2<Type, Type> _subStack;
 908    private final RecursionStack2<Type, Type> _supStack;
 909   
 910  0 public Inferencer(Set<? extends VariableType> vars) {
 911  0 _vars = vars;
 912  0 _constraints = new ConstraintSet();
 913  0 _subStack = new RecursionStack2<Type, Type>(Pair.<Type, Type>factory());
 914  0 _supStack = new RecursionStack2<Type, Type>(Pair.<Type, Type>factory());
 915    }
 916   
 917  0 public ConstraintSet constraints() { return _constraints; }
 918   
 919  0 public void subtype(final Type arg, Type param) {
 920  0 if (param.apply(_containsVar) && !(arg instanceof NullType)) {
 921  0 param.apply(new TypeAbstractVisitor_void() {
 922   
 923  0 @Override public void forVariableType(VariableType param) {
 924  0 if (_vars.contains(param)) { _constraints.addLowerBound(param, arg); }
 925    }
 926   
 927  0 @Override public void forArrayType(final ArrayType param) {
 928  0 arg.apply(new TypeAbstractVisitor_void() {
 929  0 @Override public void forArrayType(ArrayType arg) { subtype(arg.ofType(), param.ofType()); }
 930  0 @Override public void forVariableType(VariableType arg) {
 931  0 Runnable recurOnSuper = bindFirst(this, arg.symbol().upperBound());
 932  0 Runnable recurOnObject = bindFirst(this, OBJECT);
 933  0 _subStack.run(recurOnSuper, recurOnObject, arg, param);
 934    }
 935    });
 936    }
 937   
 938  0 @Override public void forParameterizedClassType(final ParameterizedClassType param) {
 939  0 arg.apply(new TypeAbstractVisitor_void() {
 940  0 @Override public void forArrayType(ArrayType arg) { CLONEABLE_AND_SERIALIZABLE.apply(this); }
 941  0 @Override public void forClassType(ClassType arg) {
 942  0 Type argSup = immediateSupertype(arg);
 943  0 if (argSup != null) { argSup.apply(this); }
 944    }
 945  0 @Override public void forParameterizedClassType(ParameterizedClassType arg) {
 946  0 if (sameClass(arg, param)) {
 947  0 for (final Pair<Type, Type> pair : zip(arg.typeArguments(), param.typeArguments())) {
 948  0 pair.second().apply(new TypeAbstractVisitor_void() {
 949  0 @Override public void forValidType(ValidType param) {
 950  0 if (pair.first() instanceof ValidType) { equal(pair.first(), param); }
 951    }
 952  0 @Override public void forWildcard(final Wildcard param) {
 953  0 Runnable recurOnWildcard = new Runnable() {
 954  0 public void run() {
 955  0 final Type paramUpper = param.symbol().upperBound();
 956  0 final Type paramLower = param.symbol().lowerBound();
 957  0 if (!paramUpper.equals(OBJECT)) {
 958  0 pair.first().apply(new TypeAbstractVisitor_void() {
 959  0 @Override public void forValidType(ValidType arg) { subtype(arg, paramUpper); }
 960  0 @Override public void forWildcard(Wildcard arg) {
 961  0 Type argUpper = arg.symbol().upperBound();
 962  0 if (!argUpper.equals(OBJECT)) { subtype(argUpper, paramUpper); }
 963    }
 964    });
 965    }
 966  0 if (!paramLower.equals(NULL)) {
 967  0 pair.first().apply(new TypeAbstractVisitor_void() {
 968  0 @Override public void forValidType(ValidType arg) { supertype(arg, paramLower); }
 969  0 @Override public void forWildcard(Wildcard arg) {
 970  0 Type argLower = arg.symbol().lowerBound();
 971  0 if (!argLower.equals(NULL)) { supertype(argLower, paramLower); }
 972    }
 973    });
 974    }
 975    }
 976    };
 977  0 _subStack.run(recurOnWildcard, pair.first(), param);
 978    }
 979    });
 980    }
 981    }
 982  0 else { forClassType(arg); }
 983    }
 984  0 @Override public void forIntersectionType(IntersectionType arg) {
 985  0 for (Type argSup : arg.ofTypes()) { argSup.apply(this); }
 986    }
 987  0 @Override public void forVariableType(VariableType arg) {
 988  0 Runnable recurOnSuper = bindFirst(this, arg.symbol().upperBound());
 989  0 Runnable recurOnObject = bindFirst(this, OBJECT);
 990  0 _subStack.run(recurOnSuper, recurOnObject, arg, param);
 991    }
 992    });
 993    }
 994   
 995    });
 996    }
 997    }
 998   
 999  0 public void supertype(final Type arg, Type param) {
 1000  0 if (param.apply(_containsVar) && !(arg instanceof NullType)) {
 1001  0 param.apply(new TypeAbstractVisitor_void() {
 1002   
 1003  0 @Override public void forVariableType(VariableType param) {
 1004  0 if (_vars.contains(param)) { _constraints.addUpperBound(param, arg); }
 1005    }
 1006   
 1007  0 @Override public void forArrayType(final ArrayType param) {
 1008  0 if (arg instanceof ArrayType) { supertype(((ArrayType) arg).ofType(), param.ofType()); }
 1009    }
 1010   
 1011  0 @Override public void forParameterizedClassType(final ParameterizedClassType param) {
 1012  0 TypeVisitorRunnable1 argVisitor = new TypeAbstractVisitor_void() {
 1013  0 @Override public void forParameterizedClassType(ParameterizedClassType arg) {
 1014  0 if (sameClass(arg, param)) {
 1015  0 for (final Pair<Type, Type> pair : zip(arg.typeArguments(), param.typeArguments())) {
 1016  0 pair.first().apply(new TypeAbstractVisitor_void() {
 1017  0 @Override public void forValidType(ValidType arg) {
 1018  0 if (pair.second() instanceof ValidType) { equal(arg, pair.second()); }
 1019    }
 1020  0 @Override public void forWildcard(final Wildcard arg) {
 1021  0 final Type argUpper = arg.symbol().upperBound();
 1022  0 final Type argLower = arg.symbol().lowerBound();
 1023  0 if (!argUpper.equals(OBJECT)) {
 1024  0 pair.second().apply(new TypeAbstractVisitor_void() {
 1025  0 @Override public void forValidType(ValidType param) { supertype(argUpper, param); }
 1026  0 @Override public void forWildcard(Wildcard param) {
 1027  0 Type paramUpper = param.symbol().upperBound();
 1028  0 if (!paramUpper.equals(OBJECT)) { supertype(argUpper, paramUpper); }
 1029    }
 1030    });
 1031    }
 1032  0 if (!argLower.equals(NULL)) {
 1033  0 pair.second().apply(new TypeAbstractVisitor_void() {
 1034  0 @Override public void forValidType(ValidType param) { subtype(argLower, param); }
 1035  0 @Override public void forWildcard(Wildcard param) {
 1036  0 Type paramLower = param.symbol().lowerBound();
 1037  0 if (!paramLower.equals(NULL)) { subtype(argLower, paramLower); }
 1038    }
 1039    });
 1040    }
 1041    }
 1042    });
 1043    }
 1044    }
 1045    else {
 1046  0 Type paramSup = immediateSupertype(param);
 1047  0 if (paramSup != null) { supertype(arg, paramSup); }
 1048    }
 1049    }
 1050    };
 1051    // avoid infinite recursion on recursive wildcards
 1052  0 _supStack.run(bindFirst(argVisitor, arg), arg, param);
 1053    }
 1054   
 1055  0 @Override public void forIntersectionType(IntersectionType param) {
 1056    // this case is not specified, but is necessary in this implementation because immediateSupertype
 1057    // may return an intersection
 1058  0 for (Type paramSup : param.ofTypes()) { supertype(arg, paramSup); }
 1059    }
 1060    });
 1061    }
 1062    }
 1063   
 1064  0 public void equal(final Type arg, Type param) {
 1065  0 if (param.apply(_containsVar) && !(arg instanceof NullType)) {
 1066  0 param.apply(new TypeAbstractVisitor_void() {
 1067   
 1068  0 @Override public void forVariableType(VariableType param) {
 1069  0 if (_vars.contains(param)) { _constraints.addEqualBound(param, arg); }
 1070    }
 1071   
 1072  0 @Override public void forArrayType(final ArrayType param) {
 1073  0 if (arg instanceof ArrayType) { equal(((ArrayType) arg).ofType(), param.ofType()); }
 1074    }
 1075   
 1076  0 @Override public void forParameterizedClassType(final ParameterizedClassType param) {
 1077  0 if (arg instanceof ParameterizedClassType) {
 1078  0 for (Pair<Type, Type> pair : zip(((ParameterizedClassType) arg).typeArguments(), param.typeArguments())) {
 1079  0 if (pair.first() instanceof ValidType && pair.second() instanceof ValidType) {
 1080  0 equal(pair.first(), pair.second());
 1081    }
 1082  0 else if (pair.first() instanceof Wildcard && pair.second() instanceof Wildcard) {
 1083  0 BoundedSymbol argBounds = ((Wildcard) pair.first()).symbol();
 1084  0 BoundedSymbol paramBounds = ((Wildcard) pair.second()).symbol();
 1085  0 if (!(argBounds.upperBound().equals(OBJECT) || paramBounds.upperBound().equals(OBJECT))) {
 1086  0 equal(argBounds.upperBound(), paramBounds.upperBound());
 1087    }
 1088  0 if (!(argBounds.lowerBound().equals(NULL) || paramBounds.lowerBound().equals(NULL))) {
 1089  0 equal(argBounds.lowerBound(), paramBounds.lowerBound());
 1090    }
 1091    }
 1092    }
 1093    }
 1094    }
 1095   
 1096    });
 1097    }
 1098    }
 1099   
 1100    private final TypeVisitorLambda<Boolean> _containsVar = new TypeAbstractVisitor<Boolean>() {
 1101    private final RecursionStack<Type> _stack = new RecursionStack<Type>(Wrapper.<Type>factory());
 1102  0 public Boolean defaultCase(Type t) { return false; }
 1103  0 @Override public Boolean forArrayType(ArrayType t) { return t.ofType().apply(this); }
 1104  0 @Override public Boolean forParameterizedClassType(ParameterizedClassType t) {
 1105  0 return checkList(t.typeArguments());
 1106    }
 1107  0 @Override public Boolean forBoundType(BoundType t) { return checkList(t.ofTypes()); }
 1108  0 @Override public Boolean forVariableType(VariableType t) {
 1109  0 return _vars.contains(t) || checkBoundedSymbol(t, t.symbol());
 1110    }
 1111  0 @Override public Boolean forWildcard(Wildcard w) { return checkBoundedSymbol(w, w.symbol()); }
 1112   
 1113  0 private Boolean checkList(Iterable<? extends Type> types) {
 1114  0 for (Type t : types) {
 1115  0 if (t.apply(this)) { return true; }
 1116    }
 1117  0 return false;
 1118    }
 1119   
 1120  0 private Boolean checkBoundedSymbol(Type t, final BoundedSymbol s) {
 1121  0 final TypeVisitor<Boolean> visitor = this; // handles this shadowing
 1122  0 Thunk<Boolean> handleBounds = new Thunk<Boolean>() {
 1123  0 public Boolean value() {
 1124  0 return s.lowerBound().apply(visitor) || s.upperBound().apply(visitor);
 1125    }
 1126    };
 1127  0 return _stack.apply(handleBounds, false, t);
 1128    }
 1129   
 1130    };
 1131    }
 1132   
 1133    }