diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java index d4d6ae852a2..cc1e1bfe68d 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java @@ -615,12 +615,23 @@ boolean incorporate(InferenceContext18 context, TypeBound [] first, TypeBound [] } } } + if (deriveTypeArgumentConstraints) { - for (ConstraintTypeFormula typeArgumentConstraint : deriveTypeArgumentConstraints(bound1, bound2, context)) { - if (!reduceOneConstraint(context, typeArgumentConstraint)) - return false; + // Try with a simpler (cheaper) approach first + for (ConstraintFormula cf : deriveTypeArgumentConstraintsSimple(bound1, bound2)) { + if (reduceOneConstraint(context, cf)) { + // No need to keep searching, the simple strategy worked + continue; + } + + // If the simple search failed, try with a more complex (and expensive) search + for (ConstraintTypeFormula cf2 : deriveTypeArgumentConstraints(bound1, bound2, context)) { + if (!reduceOneConstraint(context, cf2)) + return false; + } } } + if (iteration == 2) { TypeBound boundX = bound1; bound1 = bound2; @@ -939,6 +950,43 @@ private ConstraintTypeFormula combineWithProperTypes(Collection prope return ConstraintTypeFormula.create(left, right, boundRight.relation, isAnyLeftSoft||boundRight.isSoft); } + private List deriveTypeArgumentConstraintsSimple(TypeBound boundS, TypeBound boundT) { + /* From 18.4: + * If two bounds have the form α <: S and α <: T, and if for some generic class or interface, G, + * there exists a supertype (4.10) of S of the form G and a supertype of T of the form G, + * then for all i, 1 ≤ i ≤ n, if Si and Ti are types (not wildcards), the constraint ⟨Si = Ti⟩ is implied. + */ + // callers must ensure both relations are <: and both lefts are equal + TypeBinding[] supers = superTypesWithCommonGenericTypeSimple(boundS.right, boundT.right); + if (supers != null) + return typeArgumentEqualityConstraints(supers[0], supers[1], boundS.isSoft || boundT.isSoft); + return Collections.emptyList(); + } + + private TypeBinding[] superTypesWithCommonGenericTypeSimple(TypeBinding s, TypeBinding t) { + if (s == null || s.id == TypeIds.T_JavaLangObject || t == null || t.id == TypeIds.T_JavaLangObject) + return null; + if (TypeBinding.equalsEquals(s.original(), t.original())) { + return new TypeBinding[] { s, t }; + } + TypeBinding tSuper = t.findSuperTypeOriginatingFrom(s); + if (tSuper != null) { + return new TypeBinding[] {s, tSuper}; + } + TypeBinding[] result = superTypesWithCommonGenericTypeSimple(s.superclass(), t); + if (result != null) + return result; + ReferenceBinding[] superInterfaces = s.superInterfaces(); + if (superInterfaces != null) { + for (ReferenceBinding superInterface : superInterfaces) { + result = superTypesWithCommonGenericTypeSimple(superInterface, t); + if (result != null) + return result; + } + } + return null; + } + private List deriveTypeArgumentConstraints(TypeBound boundS, TypeBound boundT, InferenceContext18 context) { /* From 18.4: * If two bounds have the form α <: S and α <: T, and if for some generic class or interface, G, @@ -1263,7 +1311,7 @@ private boolean superOnlyRaw(TypeBinding g, TypeBinding s, LookupEnvironment env return false; } - protected List> allSuperPairsWithCommonGenericType(TypeBinding s, TypeBinding t) { + private List> allSuperPairsWithCommonGenericType(TypeBinding s, TypeBinding t) { if (s == null || s.id == TypeIds.T_JavaLangObject || t == null || t.id == TypeIds.T_JavaLangObject) return Collections.emptyList(); List> result = new ArrayList<>();