Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Lohmeier2019-02-17 13:52:23 -0500
committerStephan Herrmann2019-05-01 17:54:50 -0400
commit116c160724dfe3a8d68edaf406d0ec168fce56ef (patch)
tree1bd784b569b52f6c1d2d21b2ef4a6f4d895a3719
parent4e0281f70e20e78feae8925f35609842163cda70 (diff)
downloadeclipse.jdt.core-116c160724dfe3a8d68edaf406d0ec168fce56ef.tar.gz
eclipse.jdt.core-116c160724dfe3a8d68edaf406d0ec168fce56ef.tar.xz
eclipse.jdt.core-116c160724dfe3a8d68edaf406d0ec168fce56ef.zip
Bug 512156 - [inference] Eclipse build freezes due to generics process.
- Add innerContext argument to InferenceContext18.resumeSuspendedInference(...) to be able to detect multiple invocations for same inner context and to eliminate duplicate inference variables in this case to speed up compilation Change-Id: I0b8f36c0bf94ed1c137294143e500a05938f444e 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/GenericsRegressionTest_1_8.java149
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java12
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java24
3 files changed, 177 insertions, 8 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
index 4a3a0454b4..8a1217eb45 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
@@ -9628,4 +9628,153 @@ public void testBug508834_comment0() {
"----------\n";
runner.runNegativeTest();
}
+ public void testBug512156_3() {
+ runConformTest(
+ new String[] {
+ "TestFor3TypeParameters.java",
+ "import java.util.Objects;\n" +
+ "import java.util.stream.Stream;\n" +
+ "import java.util.stream.StreamSupport;\n" +
+ "\n" +
+ "/**\n" +
+ " * For comprehension for 3 iterables. Adapted from the http://javaslang.io library to help finding JDT performance bottlenecks.\n" +
+ " *\n" +
+ " */\n" +
+ "public class TestFor3TypeParameters {\n" +
+ "\n" +
+ " public interface Function3<T1, T2, T3, R> {\n" +
+ " R apply(T1 t1, T2 t2, T3 t3);\n" +
+ " } \n" +
+ " \n" +
+ " public static class For3<T1, T2, T3> {\n" +
+ "\n" +
+ " private final Iterable<T1> ts1;\n" +
+ " private final Iterable<T2> ts2;\n" +
+ " private final Iterable<T3> ts3;\n" +
+ "\n" +
+ " private For3(Iterable<T1> ts1, Iterable<T2> ts2, Iterable<T3> ts3) {\n" +
+ " this.ts1 = ts1;\n" +
+ " this.ts2 = ts2;\n" +
+ " this.ts3 = ts3;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Yields a result for elements of the cross product of the underlying Iterables.\n" +
+ " *\n" +
+ " * @param f\n" +
+ " * a function that maps an element of the cross product to a result\n" +
+ " * @param <R>\n" +
+ " * type of the resulting {@code Iterator} elements\n" +
+ " * @return an {@code Iterator} of mapped results\n" +
+ " */\n" +
+ " public <R> Stream<R> yield(\n" +
+ " Function3<? super T1, ? super T2, ? super T3, ? extends R> f) {\n" +
+ " Objects.requireNonNull(f, \"f is null\");\n" +
+ " return this.stream(ts1)\n" +
+ " .flatMap(t1 ->\n" +
+ " stream(ts2).flatMap(t2 -> \n" +
+ " stream(ts3).map(t3 ->\n" +
+ " f.apply(t1, t2, t3)\n" +
+ " )\n" +
+ " )\n" +
+ " );\n" +
+ " }\n" +
+ "\n" +
+ " private <T> Stream<T> stream(Iterable<T> iterable) {\n" +
+ " return StreamSupport.stream(iterable.spliterator(), false);\n" +
+ " }\n" +
+ "\n" +
+ " }\n" +
+ "}\n"
+ });
+ }
+ public void testBug512156_10() {
+ runConformTest(
+ new String[] {
+ "Test10.java",
+ "import java.util.Objects;\n" +
+ "import java.util.stream.Stream;\n" +
+ "import java.util.stream.StreamSupport;\n" +
+ "\n" +
+ "/**\n" +
+ " * For comprehension for 10 iterables. Adapted from the http://javaslang.io library to help finding JDT performance bottlenecks.\n" +
+ " *\n" +
+ " */\n" +
+ "public class Test10 {\n" +
+ "\n" +
+ " public interface Function10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R> {\n" +
+ " R apply(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10);\n" +
+ " } \n" +
+ " \n" +
+ " public static class For10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> {\n" +
+ "\n" +
+ " private final Iterable<T1> ts1;\n" +
+ " private final Iterable<T2> ts2;\n" +
+ " private final Iterable<T3> ts3;\n" +
+ " private final Iterable<T4> ts4;\n" +
+ " private final Iterable<T5> ts5;\n" +
+ " private final Iterable<T6> ts6;\n" +
+ " private final Iterable<T7> ts7;\n" +
+ " private final Iterable<T8> ts8;\n" +
+ " private final Iterable<T9> ts9;\n" +
+ " private final Iterable<T10> ts10;\n" +
+ "\n" +
+ " private For10(Iterable<T1> ts1, Iterable<T2> ts2, Iterable<T3> ts3, Iterable<T4> ts4, Iterable<T5> ts5, Iterable<T6> ts6,\n" +
+ " Iterable<T7> ts7, Iterable<T8> ts8, Iterable<T9> ts9, Iterable<T10> ts10) {\n" +
+ " this.ts1 = ts1;\n" +
+ " this.ts2 = ts2;\n" +
+ " this.ts3 = ts3;\n" +
+ " this.ts4 = ts4;\n" +
+ " this.ts5 = ts5;\n" +
+ " this.ts6 = ts6;\n" +
+ " this.ts7 = ts7;\n" +
+ " this.ts8 = ts8;\n" +
+ " this.ts9 = ts9;\n" +
+ " this.ts10 = ts10;\n" +
+ " }\n" +
+ "\n" +
+ " /**\n" +
+ " * Yields a result for elements of the cross product of the underlying Iterables.\n" +
+ " *\n" +
+ " * @param f\n" +
+ " * a function that maps an element of the cross product to a result\n" +
+ " * @param <R>\n" +
+ " * type of the resulting {@code Iterator} elements\n" +
+ " * @return an {@code Iterator} of mapped results\n" +
+ " */\n" +
+ " public <R> Stream<R> yield(\n" +
+ " Function10<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? super T7, ? super T8, ? super T9, ? super T10, ? extends R> f) {\n" +
+ " Objects.requireNonNull(f, \"f is null\");\n" +
+ " return this.stream(ts1)\n" +
+ " .flatMap(t1 ->\n" +
+ " stream(ts2).flatMap(t2 -> \n" +
+ " stream(ts3).flatMap(t3 -> \n" +
+ " stream(ts4).flatMap(t4 -> \n" +
+ " stream(ts5).flatMap(t5 -> \n" +
+ " stream(ts6).flatMap(t6 -> \n" +
+ " stream(ts7).flatMap(t7 -> \n" +
+ " stream(ts8).flatMap(t8 ->\n" +
+ " stream(ts9).flatMap(t9 ->\n" +
+ " stream(ts10).map(t10 -> /**/\n" +
+ " f.apply(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " )\n" +
+ " );\n" +
+ " }\n" +
+ "\n" +
+ " private <T> Stream<T> stream(Iterable<T> iterable) {\n" +
+ " return StreamSupport.stream(iterable.spliterator(), false);\n" +
+ " }\n" +
+ "\n" +
+ " }\n" +
+ "}\n"
+ });
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
index 0ae4780952..4e5e921e3d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
@@ -104,6 +104,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(invocation, invocation.arguments());
// Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2
+ InferenceContext18 innerCtx = null;
try {
Expression[] arguments = invocation.arguments();
TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
@@ -111,7 +112,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
argumentTypes[i] = arguments[i].resolvedType;
if (previousMethod instanceof ParameterizedGenericMethodBinding) {
// find the previous inner inference context to see what inference kind this invocation needs:
- InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
+ innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
if (innerCtx == null) {
/* No inference context -> the method was likely manufactured by Scope.findExactMethod -> assume it wasn't really poly after all.
-> proceed as for non-poly expressions.
@@ -137,7 +138,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
return FALSE;
return null; // already incorporated
} finally {
- inferenceContext.resumeSuspendedInference(prevInvocation);
+ inferenceContext.resumeSuspendedInference(prevInvocation, innerCtx);
}
} else if (this.left instanceof ConditionalExpression) {
ConditionalExpression conditional = (ConditionalExpression) this.left;
@@ -231,7 +232,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
try {
return inferenceContext.inferFunctionalInterfaceParameterization(lambda, scope, targetTypeWithWildCards);
} finally {
- inferenceContext.resumeSuspendedInference(previous);
+ inferenceContext.resumeSuspendedInference(previous, null);
}
}
}
@@ -312,8 +313,9 @@ class ConstraintExpressionFormula extends ConstraintFormula {
SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(reference, reference.createPseudoExpressions(argumentTypes));
// Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2
+ InferenceContext18 innerContext = null;
try {
- InferenceContext18 innerContext = reference.getInferenceContext((ParameterizedMethodBinding) compileTimeDecl);
+ innerContext = reference.getInferenceContext((ParameterizedMethodBinding) compileTimeDecl);
int innerInferenceKind = determineInferenceKind(compileTimeDecl, argumentTypes, innerContext);
inferInvocationApplicability(inferenceContext, original, argumentTypes, original.isConstructor()/*mimic a diamond?*/, innerInferenceKind);
if (!inferenceContext.computeB3(reference, r, original))
@@ -322,7 +324,7 @@ class ConstraintExpressionFormula extends ConstraintFormula {
} catch (InferenceFailureException e) {
return FALSE;
} finally {
- inferenceContext.resumeSuspendedInference(prevInvocation);
+ inferenceContext.resumeSuspendedInference(prevInvocation, innerContext);
}
}
TypeBinding rPrime = compileTimeDecl.isConstructor() ? compileTimeDecl.declaringClass : compileTimeDecl.returnType.capture(inferenceContext.scope, reference.sourceStart(), reference.sourceEnd());
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 2fb1f91e80..613512c4f1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -21,6 +21,7 @@ import java.util.Comparator;
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.Set;
@@ -159,6 +160,7 @@ public class InferenceContext18 {
public List<ConstraintFormula> constraintsWithUncheckedConversion;
public boolean usesUncheckedConversion;
public InferenceContext18 outerContext;
+ private Set<InferenceContext18> seenInnerContexts;
Scope scope;
LookupEnvironment environment;
ReferenceBinding object; // java.lang.Object
@@ -1617,18 +1619,24 @@ public class InferenceContext18 {
this.usesUncheckedConversion = innerCtx.usesUncheckedConversion;
}
- public void resumeSuspendedInference(SuspendedInferenceRecord record) {
+ public void resumeSuspendedInference(SuspendedInferenceRecord record, InferenceContext18 innerContext) {
// merge inference variables:
+ boolean firstTime = collectInnerContext(innerContext);
if (this.inferenceVariables == null) { // no new ones, assume we aborted prematurely
this.inferenceVariables = record.inferenceVariables;
+ } else if(!firstTime) {
+ // Use a set to eliminate duplicates.
+ final Set<InferenceVariable> uniqueVariables = new LinkedHashSet<>();
+ uniqueVariables.addAll(Arrays.asList(record.inferenceVariables));
+ uniqueVariables.addAll(Arrays.asList(this.inferenceVariables));
+ this.inferenceVariables = uniqueVariables.toArray(new InferenceVariable[uniqueVariables.size()]);
} else {
int l1 = this.inferenceVariables.length;
int l2 = record.inferenceVariables.length;
- // move to back, add previous to front:
System.arraycopy(this.inferenceVariables, 0, this.inferenceVariables=new InferenceVariable[l1+l2], l2, l1);
System.arraycopy(record.inferenceVariables, 0, this.inferenceVariables, 0, l2);
}
-
+
// replace invocation site & arguments:
this.currentInvocation = record.site;
this.invocationArguments = record.invocationArguments;
@@ -1636,6 +1644,16 @@ public class InferenceContext18 {
this.usesUncheckedConversion = record.usesUncheckedConversion;
}
+ private boolean collectInnerContext(final InferenceContext18 innerContext) {
+ if(innerContext == null) {
+ return false;
+ }
+ if(this.seenInnerContexts == null) {
+ this.seenInnerContexts = new HashSet<>();
+ }
+ return this.seenInnerContexts.add(innerContext);
+ }
+
private Substitution getResultSubstitution(final BoundSet result) {
return new Substitution() {
@Override

Back to the top