From 116c160724dfe3a8d68edaf406d0ec168fce56ef Mon Sep 17 00:00:00 2001 From: Sebastian Lohmeier Date: Sun, 17 Feb 2019 19:52:23 +0100 Subject: 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 --- .../regression/GenericsRegressionTest_1_8.java | 149 +++++++++++++++++++++ .../lookup/ConstraintExpressionFormula.java | 12 +- .../compiler/lookup/InferenceContext18.java | 24 +++- 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 {\n" + + " R apply(T1 t1, T2 t2, T3 t3);\n" + + " } \n" + + " \n" + + " public static class For3 {\n" + + "\n" + + " private final Iterable ts1;\n" + + " private final Iterable ts2;\n" + + " private final Iterable ts3;\n" + + "\n" + + " private For3(Iterable ts1, Iterable ts2, Iterable 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 \n" + + " * type of the resulting {@code Iterator} elements\n" + + " * @return an {@code Iterator} of mapped results\n" + + " */\n" + + " public Stream yield(\n" + + " Function3 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 Stream stream(Iterable 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 {\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 {\n" + + "\n" + + " private final Iterable ts1;\n" + + " private final Iterable ts2;\n" + + " private final Iterable ts3;\n" + + " private final Iterable ts4;\n" + + " private final Iterable ts5;\n" + + " private final Iterable ts6;\n" + + " private final Iterable ts7;\n" + + " private final Iterable ts8;\n" + + " private final Iterable ts9;\n" + + " private final Iterable ts10;\n" + + "\n" + + " private For10(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6,\n" + + " Iterable ts7, Iterable ts8, Iterable ts9, Iterable 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 \n" + + " * type of the resulting {@code Iterator} elements\n" + + " * @return an {@code Iterator} of mapped results\n" + + " */\n" + + " public Stream yield(\n" + + " Function10 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 Stream stream(Iterable 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 constraintsWithUncheckedConversion; public boolean usesUncheckedConversion; public InferenceContext18 outerContext; + private Set 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 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 -- cgit v1.2.3