1219 * equals if they share the same type symbol. |
1219 * equals if they share the same type symbol. |
1220 */ |
1220 */ |
1221 TypeRelation isSameTypeLoose = new LooseSameTypeVisitor(); |
1221 TypeRelation isSameTypeLoose = new LooseSameTypeVisitor(); |
1222 |
1222 |
1223 private class LooseSameTypeVisitor extends SameTypeVisitor { |
1223 private class LooseSameTypeVisitor extends SameTypeVisitor { |
|
1224 |
|
1225 /** cache of the type-variable pairs being (recursively) tested. */ |
|
1226 private Set<TypePair> cache = new HashSet<>(); |
|
1227 |
1224 @Override |
1228 @Override |
1225 boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { |
1229 boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { |
1226 return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound()); |
1230 return tv1.tsym == tv2.tsym && checkSameBounds(tv1, tv2); |
1227 } |
1231 } |
1228 @Override |
1232 @Override |
1229 protected boolean containsTypes(List<Type> ts1, List<Type> ts2) { |
1233 protected boolean containsTypes(List<Type> ts1, List<Type> ts2) { |
1230 return containsTypeEquivalent(ts1, ts2); |
1234 return containsTypeEquivalent(ts1, ts2); |
|
1235 } |
|
1236 |
|
1237 /** |
|
1238 * Since type-variable bounds can be recursive, we need to protect against |
|
1239 * infinite loops - where the same bounds are checked over and over recursively. |
|
1240 */ |
|
1241 private boolean checkSameBounds(TypeVar tv1, TypeVar tv2) { |
|
1242 TypePair p = new TypePair(tv1, tv2, true); |
|
1243 if (cache.add(p)) { |
|
1244 try { |
|
1245 return visit(tv1.getUpperBound(), tv2.getUpperBound()); |
|
1246 } finally { |
|
1247 cache.remove(p); |
|
1248 } |
|
1249 } else { |
|
1250 return false; |
|
1251 } |
1231 } |
1252 } |
1232 }; |
1253 }; |
1233 |
1254 |
1234 /** |
1255 /** |
1235 * Strict type-equality relation - type variables are considered |
1256 * Strict type-equality relation - type variables are considered |
3374 } |
3395 } |
3375 // where |
3396 // where |
3376 class TypePair { |
3397 class TypePair { |
3377 final Type t1; |
3398 final Type t1; |
3378 final Type t2; |
3399 final Type t2; |
|
3400 boolean strict; |
|
3401 |
3379 TypePair(Type t1, Type t2) { |
3402 TypePair(Type t1, Type t2) { |
|
3403 this(t1, t2, false); |
|
3404 } |
|
3405 |
|
3406 TypePair(Type t1, Type t2, boolean strict) { |
3380 this.t1 = t1; |
3407 this.t1 = t1; |
3381 this.t2 = t2; |
3408 this.t2 = t2; |
|
3409 this.strict = strict; |
3382 } |
3410 } |
3383 @Override |
3411 @Override |
3384 public int hashCode() { |
3412 public int hashCode() { |
3385 return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2); |
3413 return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2); |
3386 } |
3414 } |
3387 @Override |
3415 @Override |
3388 public boolean equals(Object obj) { |
3416 public boolean equals(Object obj) { |
3389 if (!(obj instanceof TypePair)) |
3417 if (!(obj instanceof TypePair)) |
3390 return false; |
3418 return false; |
3391 TypePair typePair = (TypePair)obj; |
3419 TypePair typePair = (TypePair)obj; |
3392 return isSameType(t1, typePair.t1) |
3420 return isSameType(t1, typePair.t1, strict) |
3393 && isSameType(t2, typePair.t2); |
3421 && isSameType(t2, typePair.t2, strict); |
3394 } |
3422 } |
3395 } |
3423 } |
3396 Set<TypePair> mergeCache = new HashSet<TypePair>(); |
3424 Set<TypePair> mergeCache = new HashSet<TypePair>(); |
3397 private Type merge(Type c1, Type c2) { |
3425 private Type merge(Type c1, Type c2) { |
3398 ClassType class1 = (ClassType) c1; |
3426 ClassType class1 = (ClassType) c1; |