--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Jun 09 10:17:16 2014 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Mon Jun 09 12:54:02 2014 +0100
@@ -1212,17 +1212,38 @@
TypeRelation isSameTypeLoose = new LooseSameTypeVisitor();
private class LooseSameTypeVisitor extends SameTypeVisitor {
+
+ /** cache of the type-variable pairs being (recursively) tested. */
+ private Set<TypePair> cache = new HashSet<>();
+
@Override
boolean sameTypeVars(TypeVar tv1, TypeVar tv2) {
- return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound());
+ return tv1.tsym == tv2.tsym && checkSameBounds(tv1, tv2);
}
@Override
protected boolean containsTypes(List<Type> ts1, List<Type> ts2) {
return containsTypeEquivalent(ts1, ts2);
}
- }
-
- /**
+
+ /**
+ * Since type-variable bounds can be recursive, we need to protect against
+ * infinite loops - where the same bounds are checked over and over recursively.
+ */
+ private boolean checkSameBounds(TypeVar tv1, TypeVar tv2) {
+ TypePair p = new TypePair(tv1, tv2, true);
+ if (cache.add(p)) {
+ try {
+ return visit(tv1.getUpperBound(), tv2.getUpperBound());
+ } finally {
+ cache.remove(p);
+ }
+ } else {
+ return false;
+ }
+ }
+ };
+
+ /**
* Strict type-equality relation - type variables are considered
* equals if they share the same object identity.
*/
@@ -3396,9 +3417,16 @@
class TypePair {
final Type t1;
final Type t2;
+ boolean strict;
+
TypePair(Type t1, Type t2) {
+ this(t1, t2, false);
+ }
+
+ TypePair(Type t1, Type t2, boolean strict) {
this.t1 = t1;
this.t2 = t2;
+ this.strict = strict;
}
@Override
public int hashCode() {
@@ -3409,8 +3437,8 @@
if (!(obj instanceof TypePair))
return false;
TypePair typePair = (TypePair)obj;
- return isSameType(t1, typePair.t1)
- && isSameType(t2, typePair.t2);
+ return isSameType(t1, typePair.t1, strict)
+ && isSameType(t2, typePair.t2, strict);
}
}
Set<TypePair> mergeCache = new HashSet<>();