Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Lohmeier2019-03-30 19:38:03 +0000
committerStephan Herrmann2019-08-15 19:50:27 +0000
commit372c6048cc1b21d8a4ceb948bf5eaecaa40576c9 (patch)
tree49c5753660e77ef7af21dfce8d4bf9b641b84612
parent80c9526e9d140ebd12dc7fda8ba293405ffaacf6 (diff)
downloadeclipse.jdt.core-372c6048cc1b21d8a4ceb948bf5eaecaa40576c9.tar.gz
eclipse.jdt.core-372c6048cc1b21d8a4ceb948bf5eaecaa40576c9.tar.xz
eclipse.jdt.core-372c6048cc1b21d8a4ceb948bf5eaecaa40576c9.zip
Bug 543480 - [compiler][inference] Very slowI20190816-1800I20190816-0155
Instead of incorporating the type arguments of parameterized dependencies one by one, they are incorporated at once - but only if there are proper types for all inference variables in all type arguments of a parameterized dependency. Change-Id: Ic36fecb7b562a31d049b92381fa535400bfb129f Signed-off-by: Sebastian Lohmeier <sebastian@monochromata.de>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java171
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java7
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java147
3 files changed, 306 insertions, 19 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 20da9ff124..a1248f79fe 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -52586,4 +52586,175 @@ public void testBug541772_typeannotations() {
compilerOptions,
null /*customRequestor*/);
}
+/**
+ * This test targets the optimization for parameterized dependencies in {@code BoundSet.combineSameSameWithProperType(...)}.
+ */
+public void testBug543480BasedOnTest2FromComment4ToSameSameOptimization() {
+ if (this.complianceLevel >= ClassFileConstants.JDK1_8) {
+ final long durationFor2TypeParameters = compileTimesAfterWarmup(() -> runConformTest(
+ new String[] {
+ "Test2_2.java",
+ "public class Test2_2 {\n" +
+ " void test() {\n" +
+ " m(s(\n" +
+ " f(1),\n" +
+ " f(2)\n" +
+ " ));\n" +
+ " }\n" +
+ "\n" +
+ " static <R> R m(S<R> s) { return null; }\n" +
+ " static <T> F<T> f(T t) { return null; }\n" +
+ " static <T1> S<R1<T1>> s(F<T1> t1) { return null; }\n" +
+ " static <T1, T2> S<R2<T1, T2>> s(F<T1> t1, F<T2> t2) { return null; }\n" +
+ "}\n" +
+ "interface F<T> {}\n" +
+ "interface S<R> {}\n" +
+ "interface R1<T1> {}\n" +
+ "interface R2<T1, T2> {}\n"
+ }));
+ final long durationFor11TypeParameters = compileTimesAfterWarmup(() -> runConformTest(
+ new String[] {
+ "Test2_11.java",
+ "public class Test2_11 {\n" +
+ " void test() {\n" +
+ " m(s(\n" +
+ " f(1),\n" +
+ " f(2),\n" +
+ " f(3),\n" +
+ " f(4),\n" +
+ " f(5),\n" +
+ " f(6),\n" +
+ " f(7),\n" +
+ " f(8),\n" +
+ " f(9),\n" +
+ " f(10),\n" +
+ " f(11)\n" +
+ " ));\n" +
+ " }\n" +
+ "\n" +
+ " static <R> R m(S<R> s) { return null; }\n" +
+ " static <T> F<T> f(T t) { return null; }\n" +
+ " static <T1> S<R1<T1>> s(F<T1> t1) { return null; }\n" +
+ " static <T1, T2> S<R2<T1, T2>> s(F<T1> t1, F<T2> t2) { return null; }\n" +
+ " static <T1, T2, T3> S<R3<T1, T2, T3>> s(F<T1> t1, F<T2> t2, F<T3> t3) { return null; }\n" +
+ " static <T1, T2, T3, T4> S<R4<T1, T2, T3, T4>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5> S<R5<T1, T2, T3, T4, T5>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6> S<R6<T1, T2, T3, T4, T5, T6>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6, T7> S<R7<T1, T2, T3, T4, T5, T6, T7>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6, F<T7> t7) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6, T7, T8> S<R8<T1, T2, T3, T4, T5, T6, T7, T8>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6, F<T7> t7, F<T8> t8) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6, T7, T8, T9> S<R9<T1, T2, T3, T4, T5, T6, T7, T8, T9>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6, F<T7> t7, F<T8> t8, F<T9> t9) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> S<R10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6, F<T7> t7, F<T8> t8, F<T9> t9, F<T10> t10) { return null; }\n" +
+ " static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> S<R11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>> s(F<T1> t1, F<T2> t2, F<T3> t3, F<T4> t4, F<T5> t5, F<T6> t6, F<T7> t7, F<T8> t8, F<T9> t9, F<T10> t10, F<T11> t11) { return null; }\n" +
+ "}\n" +
+ "interface F<T> {}\n" +
+ "interface S<R> {}\n" +
+ "interface R1<T1> {}\n" +
+ "interface R2<T1, T2> {}\n" +
+ "interface R3<T1, T2, T3> {}\n" +
+ "interface R4<T1, T2, T3, T4> {}\n" +
+ "interface R5<T1, T2, T3, T4, T5> {}\n" +
+ "interface R6<T1, T2, T3, T4, T5, T6> {}\n" +
+ "interface R7<T1, T2, T3, T4, T5, T6, T7> {}\n" +
+ "interface R8<T1, T2, T3, T4, T5, T6, T7, T8> {}\n" +
+ "interface R9<T1, T2, T3, T4, T5, T6, T7, T8, T9> {}\n" +
+ "interface R10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> {}\n" +
+ "interface R11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> {}\n"
+ }));
+ // Time complexity should grow roughly linearly, not O(2^n)
+ // To make the test robust, it tests for the same order of magnitude only, i.e. factor 10.
+ assertCompileTimes(durationFor2TypeParameters, 10, durationFor11TypeParameters);
+ }
+}
+/**
+ * This test targets the optimization for parameterized dependencies in {@code BoundSet.combineSameSubSuperWithProperType(...)}.
+ */
+public void testBug543480WithSameSubSuperOptimization() {
+ if (this.complianceLevel >= ClassFileConstants.JDK1_8) {
+ final long durationFor2TypeParameters = compileTimesAfterWarmup(() -> runConformTest(
+ new String[] {
+ "WithParameterizedDependencies_2.java",
+ "abstract class WithParameterizedDependencies_2 {\n" +
+ " <T1, T2> \n" +
+ " Type1<T1, T2>\n" +
+ " s1(Type1<T1, T2> t) {\n" +
+ // This line causes the optimization in BoundSet.combineSameSubSuperWithProperType(...) to be effective.
+ " return s2(new Type1<>(t));\n" +
+ " }\n" +
+ " abstract <E> E s2(E e);\n" +
+ "}\n" +
+ "class Type1<T1, T2> {\n" +
+ " Type1(final Type1<T1, T2> l) {}" +
+ "}\n"
+ }));
+ final long durationFor12TypeParameters = compileTimesAfterWarmup(() -> runConformTest(
+ new String[] {
+ "WithParameterizedDependencies_12.java",
+ "abstract class WithParameterizedDependencies_12 {\n" +
+ " <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> \n" +
+ " Type1<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>\n" +
+ " s1(Type1<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> t) {\n" +
+ // This line causes the optimization in BoundSet.combineSameSubSuperWithProperType(...) to be effective.
+ " return s2(new Type1<>(t));\n" +
+ " }\n" +
+ " abstract <E> E s2(E e);\n" +
+ "}\n" +
+ "class Type1<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> {\n" +
+ " Type1(final Type1<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> l) {}" +
+ "}\n"
+ }));
+ // Time complexity should grow roughly linearly, not O(2^n).
+ // To make the test robust, it tests for the same order of magnitude only, i.e. factor 10.
+ assertCompileTimes(durationFor2TypeParameters, 10, durationFor12TypeParameters);
+ }
+}
+/**
+ * An earlier version of the fix for bug 543480 causes a NullPointerException when compiling this code.
+ */
+public void testBug543480WithoutNullPointerExceptionDuringBytecodeGeneration() {
+ if (this.complianceLevel >= ClassFileConstants.JDK1_8) {
+ runConformTest(
+ new String[] {
+ "Test.java",
+ "import java.util.function.BiConsumer;\n" +
+ "\n" +
+ "public class Test {\n" +
+ " \n" +
+ " interface I0<T extends I0<T>> {}\n" +
+ "\n" +
+ " class Type<T extends I0<T>, D> {\n" +
+ " // TODO: The problem might be that BiConsumer is not declared in the same file?\n" +
+ " public Type(final BiConsumer<T, D> b) { }\n" +
+ " }\n" +
+ "\n" +
+ " public void foo() {\n" +
+ " new Type<>((unused0, unused1) -> {});\n" +
+ " }\n" +
+ "}"
+ });
+ }
+}
+
+protected void assertCompileTimes(final long shortTime, final double factor, final long longTime) {
+ assertTrue(longTime + " should be less than " + factor + "x the compile time of " + shortTime,
+ longTime < factor*shortTime);
+}
+
+protected long compileTimesAfterWarmup(final Runnable compileTask) {
+ // warm up
+ duration(compileTask);
+ // average
+ return (duration(compileTask) + duration(compileTask) +
+ duration(compileTask) + duration(compileTask) +
+ duration(compileTask) + duration(compileTask)) / 6;
}
+
+protected long duration(final Runnable runnable) {
+ final long startMs = System.currentTimeMillis();
+ runnable.run();
+ final long endMs = System.currentTimeMillis();
+ final long duration = endMs-startMs;
+ return duration;
+}
+
+}
+
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
index 9c015d394c..6760a7bddd 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/TestVerifier.java
@@ -660,13 +660,16 @@ public boolean verifyClassFilesThrowingError(String sourceFilePath, String class
*/
private void waitForFullBuffers() {
String endString = VerifyTests.class.getName();
- int count = 50;
+ int count = 60;
+ int waitMs = 1;
int errorEndStringStart = this.errorBuffer.toString().indexOf(endString);
int outputEndStringStart = this.outputBuffer.toString().indexOf(endString);
while (errorEndStringStart == -1 || outputEndStringStart == -1) {
try {
- Thread.sleep(100);
+ Thread.sleep(waitMs);
} catch (InterruptedException e) {
+ } finally {
+ if(waitMs < 100) waitMs *= 2;
}
if (--count == 0) return;
errorEndStringStart = this.errorBuffer.toString().indexOf(endString);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index 78cff89fd4..d004bd72d5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -16,14 +16,21 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
+
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.stream.Stream;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
@@ -33,6 +40,18 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard;
*/
class BoundSet {
+ /**
+ * Set the identically-named system property to false to disable the
+ * optimization implemented to fix Bug 543480.
+ */
+ public static boolean enableOptimizationForBug543480 = true;
+ static {
+ String enableOptimizationForBug543480Property = System.getProperty("enableOptimizationForBug543480"); //$NON-NLS-1$
+ if(enableOptimizationForBug543480Property != null) {
+ enableOptimizationForBug543480 = enableOptimizationForBug543480Property.equalsIgnoreCase("true"); //$NON-NLS-1$
+ }
+ }
+
static final BoundSet TRUE = new BoundSet(); // empty set of bounds
static final BoundSet FALSE = new BoundSet(); // pseudo bounds
@@ -536,18 +555,18 @@ class BoundSet {
case ReductionResult.SAME:
switch (boundJ.relation) {
case ReductionResult.SAME:
- newConstraint = combineSameSame(boundI, boundJ);
+ newConstraint = combineSameSame(boundI, boundJ, first, next);
break;
case ReductionResult.SUBTYPE:
case ReductionResult.SUPERTYPE:
- newConstraint = combineSameSubSuper(boundI, boundJ);
+ newConstraint = combineSameSubSuper(boundI, boundJ, first, next);
break;
}
break;
case ReductionResult.SUBTYPE:
switch (boundJ.relation) {
case ReductionResult.SAME:
- newConstraint = combineSameSubSuper(boundJ, boundI);
+ newConstraint = combineSameSubSuper(boundJ, boundI, first, next);
break;
case ReductionResult.SUPERTYPE:
newConstraint = combineSuperAndSub(boundJ, boundI);
@@ -561,7 +580,7 @@ class BoundSet {
case ReductionResult.SUPERTYPE:
switch (boundJ.relation) {
case ReductionResult.SAME:
- newConstraint = combineSameSubSuper(boundJ, boundI);
+ newConstraint = combineSameSubSuper(boundJ, boundI, first, next);
break;
case ReductionResult.SUBTYPE:
newConstraint = combineSuperAndSub(boundI, boundJ);
@@ -726,7 +745,7 @@ class BoundSet {
reduceOneConstraint(context, formula);
}
- private ConstraintTypeFormula combineSameSame(TypeBound boundS, TypeBound boundT) {
+ private ConstraintTypeFormula combineSameSame(TypeBound boundS, TypeBound boundT, TypeBound[] firstBounds, TypeBound[] nextBounds) {
// α = S and α = T imply ⟨S = T⟩
if (TypeBinding.equalsEquals(boundS.left, boundT.left))
@@ -734,19 +753,26 @@ class BoundSet {
// match against more shapes:
ConstraintTypeFormula newConstraint;
- newConstraint = combineSameSameWithProperType(boundS, boundT);
+ newConstraint = combineSameSameWithProperType(boundS, boundT, firstBounds, nextBounds);
if (newConstraint != null)
return newConstraint;
- newConstraint = combineSameSameWithProperType(boundT, boundS);
+ newConstraint = combineSameSameWithProperType(boundT, boundS, firstBounds, nextBounds);
if (newConstraint != null)
return newConstraint;
return null;
}
// pre: boundLeft.left != boundRight.left
- private ConstraintTypeFormula combineSameSameWithProperType(TypeBound boundLeft, TypeBound boundRight) {
+ private ConstraintTypeFormula combineSameSameWithProperType(TypeBound boundLeft, TypeBound boundRight,
+ TypeBound[] firstBounds, TypeBound[] nextBounds) {
// α = U and S = T imply ⟨S[α:=U] = T[α:=U]⟩
TypeBinding u = boundLeft.right;
+ if (enableOptimizationForBug543480 && isParameterizedDependency(boundRight)) {
+ // Performance optimization: do not incorporate arguments one by one, which yielt 2^n new bounds (n=number of type arguments) in the past.
+ // Instead, all arguments of a parameterized dependency are incorporated at once - but only when they are available.
+ return incorporateIntoParameterizedDependencyIfAllArgumentsAreProperTypes(boundRight,
+ firstBounds, nextBounds);
+ }
if (u.isProperType(true)) {
InferenceVariable alpha = boundLeft.left;
TypeBinding left = boundRight.left; // no substitution since S inference variable and (S != α) per precondition
@@ -756,7 +782,7 @@ class BoundSet {
return null;
}
- private ConstraintTypeFormula combineSameSubSuper(TypeBound boundS, TypeBound boundT) {
+ private ConstraintTypeFormula combineSameSubSuper(TypeBound boundS, TypeBound boundT, TypeBound[] firstBounds, TypeBound[] nextBounds) {
// α = S and α <: T imply ⟨S <: T⟩
// α = S and T <: α imply ⟨T <: S⟩
InferenceVariable alpha = boundS.left;
@@ -783,20 +809,33 @@ class BoundSet {
return ConstraintTypeFormula.create(t, s, boundT.relation, boundT.isSoft||boundS.isSoft);
}
}
+ return combineSameSubSuperWithProperType(boundS, boundT, alpha, firstBounds, nextBounds);
+ }
+
+ // pre: boundLeft.left != boundRight.left
+ // pre: boundLeft.left != boundRight.right
+ private ConstraintTypeFormula combineSameSubSuperWithProperType(TypeBound boundLeft, TypeBound boundRight,
+ InferenceVariable alpha, TypeBound[] firstBounds, TypeBound[] nextBounds) {
+ // α = U and S <: T imply ⟨S[α:=U] <: T[α:=U]⟩
+ TypeBinding u = boundLeft.right;
- // α = U and S <: T imply ⟨S[α:=U] <: T[α:=U]⟩
- TypeBinding u = boundS.right;
+ if (enableOptimizationForBug543480 && isParameterizedDependency(boundRight)) {
+ // Performance optimization: do not incorporate arguments one by one, which yielt 2^n new bounds (n=number of type arguments) in the past.
+ // Instead, all arguments of a parameterized dependency are incorporated at once - but only when they are available.
+ return incorporateIntoParameterizedDependencyIfAllArgumentsAreProperTypes(boundRight,
+ firstBounds, nextBounds);
+ }
if (u.isProperType(true)) {
- boolean substitute = TypeBinding.equalsEquals(alpha, boundT.left);
- TypeBinding left = substitute ? u : boundT.left;
- TypeBinding right = boundT.right.substituteInferenceVariable(alpha, u);
- substitute |= TypeBinding.notEquals(right, boundT.right);
+ boolean substitute = TypeBinding.equalsEquals(alpha, boundRight.left);
+ TypeBinding left = substitute ? u : boundRight.left;
+ TypeBinding right = boundRight.right.substituteInferenceVariable(alpha, u);
+ substitute |= TypeBinding.notEquals(right, boundRight.right);
if (substitute) // avoid redundant constraint
- return ConstraintTypeFormula.create(left, right, boundT.relation, boundT.isSoft||boundS.isSoft);
+ return ConstraintTypeFormula.create(left, right, boundRight.relation, boundRight.isSoft||boundLeft.isSoft);
}
return null;
}
-
+
private ConstraintTypeFormula combineSuperAndSub(TypeBound boundS, TypeBound boundT) {
// permutations of: S <: α and α <: T imply ⟨S <: T⟩
InferenceVariable alpha = boundS.left;
@@ -824,6 +863,80 @@ class BoundSet {
return null;
}
+ private boolean isParameterizedDependency(TypeBound typeBound) {
+ return typeBound.right.kind() == Binding.PARAMETERIZED_TYPE
+ && !typeBound.right.isProperType(true) /* is a dependency, not a type bound */
+ && typeBound.right.isParameterizedTypeWithActualArguments();
+ }
+
+ private ConstraintTypeFormula incorporateIntoParameterizedDependencyIfAllArgumentsAreProperTypes(TypeBound typeBound,
+ TypeBound[] firstBounds, TypeBound[] nextBounds) {
+ Collection<TypeBound> properTypesForAllInferenceVariables = getProperTypesForAllInferenceVariablesOrNull((ParameterizedTypeBinding)typeBound.right, firstBounds, nextBounds);
+ if (null != properTypesForAllInferenceVariables) {
+ return combineWithProperTypes(properTypesForAllInferenceVariables, typeBound);
+ }
+ return null;
+ }
+
+ private Collection<TypeBound> getProperTypesForAllInferenceVariablesOrNull(ParameterizedTypeBinding parameterizedType,
+ TypeBound[] firstBounds, TypeBound[] nextBounds) {
+ final Map<InferenceVariable,TypeBound> properTypesByInferenceVariable = properTypesByInferenceVariable(firstBounds, nextBounds);
+ if(properTypesByInferenceVariable.size() == 0) {
+ return null;
+ }
+ final Set<InferenceVariable> inferenceVariables = getInferenceVariables(parameterizedType);
+ if(properTypesByInferenceVariable.keySet().containsAll(inferenceVariables)) {
+ return properTypesByInferenceVariable.values();
+ }
+ return null;
+ }
+
+ private Map<InferenceVariable,TypeBound> properTypesByInferenceVariable(TypeBound[] firstBounds, TypeBound[] nextBounds) {
+ return getBoundsStream(firstBounds, nextBounds)
+ .filter(bound -> bound.relation == ReductionResult.SAME)
+ .filter(bound -> bound.right.isProperType(true))
+ .collect(toMap(bound -> bound.left, identity(),
+ // If nextBounds and firstBounds have a bound for the IV, prefer the newer one from nextBounds.
+ (boundFromNextBounds, boundFromFirstBounds) -> boundFromNextBounds));
+ }
+
+ private Stream<TypeBound> getBoundsStream(TypeBound[] firstBounds, TypeBound[] nextBounds) {
+ if(firstBounds == nextBounds) {
+ return Arrays.stream(firstBounds);
+ }
+ // The next bounds are considered initially because it seems more
+ // likely that they contain the new bounds that enable successful
+ // incorporation in this run in case no incorporation was possible
+ // in previous runs.
+ return Stream.concat(Arrays.stream(nextBounds), Arrays.stream(firstBounds));
+ }
+
+ private Set<InferenceVariable> getInferenceVariables(ParameterizedTypeBinding parameterizedType) {
+ final Set<InferenceVariable> inferenceVariables = new LinkedHashSet<>();
+ for(final TypeBinding argument: parameterizedType.arguments) {
+ argument.collectInferenceVariables(inferenceVariables);
+ }
+ return inferenceVariables;
+ }
+
+ private ConstraintTypeFormula combineWithProperTypes(Collection<TypeBound> properTypesForAllInferenceVariables, TypeBound boundRight) {
+ // either: α = U, β = V, ... and S = T imply ⟨S[α:=U, β:=V, ...] = T[α:=U, β:=V, ...]⟩
+ // or: α = U, β = V, ... and S <: T imply ⟨S[α:=U, β:=V, ...] <: T[α:=U, β:=V, ...]⟩
+ if(properTypesForAllInferenceVariables.size() == 0) {
+ return null;
+ }
+ boolean isAnyLeftSoft = false;
+ InferenceVariable left = boundRight.left;
+ TypeBinding right = boundRight.right;
+ for(final TypeBound properTypeForInferenceVariable: properTypesForAllInferenceVariables) {
+ final TypeBound boundLeft = properTypeForInferenceVariable;
+ final InferenceVariable alpha = boundLeft.left;
+ final TypeBinding u = boundLeft.right;
+ isAnyLeftSoft |= boundLeft.isSoft;
+ right = right.substituteInferenceVariable(alpha, u);
+ }
+ return ConstraintTypeFormula.create(left, right, boundRight.relation, isAnyLeftSoft||boundRight.isSoft);
+ }
private ConstraintTypeFormula[] deriveTypeArgumentConstraints(TypeBound boundS, TypeBound boundT) {
/* From 18.4:

Back to the top