diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index 47ac9d83b16e..142674697201 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -218,54 +218,24 @@ public class InferenceIncorporationPhase { if (inferenceVariable.getInstantiation() != PsiType.NULL) continue; Map> boundsMap = myCurrentBounds.remove(inferenceVariable); if (boundsMap == null) continue; - final Collection eqBounds = boundsMap.get(InferenceBound.EQ); - final List upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); - final List lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); - needFurtherIncorporation |= crossVariables(inferenceVariable, upperBounds, lowerBounds, InferenceBound.LOWER); - needFurtherIncorporation |= crossVariables(inferenceVariable, lowerBounds, upperBounds, InferenceBound.UPPER); - - if (eqBounds != null) { - needFurtherIncorporation |= eqCrossVariables(inferenceVariable, eqBounds); + final Set upperBounds = boundsMap.get(InferenceBound.UPPER); + final Set lowerBounds = boundsMap.get(InferenceBound.LOWER); + if (upperBounds != null) { + needFurtherIncorporation |= crossVariables(inferenceVariable, upperBounds, lowerBounds, InferenceBound.LOWER); + } + if (lowerBounds != null) { + needFurtherIncorporation |= crossVariables(inferenceVariable, lowerBounds, upperBounds, InferenceBound.UPPER); } } return !needFurtherIncorporation; } - /** - * a = b imply every bound of a matches a bound of b and vice versa - */ - private boolean eqCrossVariables(InferenceVariable inferenceVariable, Collection eqBounds) { - boolean needFurtherIncorporation = false; - for (PsiType eqBound : eqBounds) { - final InferenceVariable inferenceVar = mySession.getInferenceVariable(eqBound); - if (inferenceVar != null) { - for (InferenceBound inferenceBound : InferenceBound.values()) { - final List oldVarBounds = inferenceVar.getReadOnlyBounds(inferenceBound); - final List oldVariableBounds = inferenceVariable.getReadOnlyBounds(inferenceBound); - - for (PsiType bound : oldVariableBounds) { - if (mySession.getInferenceVariable(bound) != inferenceVar) { - needFurtherIncorporation |= inferenceVar.addBound(bound, inferenceBound, this); - } - } - - for (PsiType bound : oldVarBounds) { - if (mySession.getInferenceVariable(bound) != inferenceVariable) { - needFurtherIncorporation |= inferenceVariable.addBound(bound, inferenceBound, this); - } - } - } - } - } - return needFurtherIncorporation; - } - /** * a < b & S <: a & b <: T imply S <: b & a <: T */ private boolean crossVariables(InferenceVariable inferenceVariable, - List upperBounds, - List lowerBounds, + Collection upperBounds, + Collection lowerBounds, InferenceBound inferenceBound) { final InferenceBound oppositeBound = inferenceBound == InferenceBound.LOWER @@ -276,8 +246,10 @@ public class InferenceIncorporationPhase { final InferenceVariable inferenceVar = mySession.getInferenceVariable(upperBound); if (inferenceVar != null && inferenceVariable != inferenceVar) { - for (PsiType lowerBound : lowerBounds) { - result |= inferenceVar.addBound(lowerBound, inferenceBound, this); + if (lowerBounds != null) { + for (PsiType lowerBound : lowerBounds) { + result |= inferenceVar.addBound(lowerBound, inferenceBound, this); + } } for (PsiType varUpperBound : inferenceVar.getBounds(oppositeBound)) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/DiamondConstructorCallPassedToVarargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/DiamondConstructorCallPassedToVarargs.java new file mode 100644 index 000000000000..532e66160744 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/DiamondConstructorCallPassedToVarargs.java @@ -0,0 +1,167 @@ +import java.util.*; +import java.util.stream.*; + +interface Graph extends Iterable { + double distance(T from, T to); + T startVertex(); + default Stream stream() { + return StreamSupport.stream(spliterator(), false); + } +} + +class GeometricGraph> implements Graph> { + private Point[] vertices; + @SafeVarargs + public GeometricGraph(Point... vertices) { + this.vertices = vertices; + } + @Override public double distance(Point from, Point to) { + double dx = to.x - from.x; + double dy = to.y - from.y; + return Math.sqrt(dx * dx + dy * dy); + } + @Override public Point startVertex() { + return vertices[0]; + } + @Override public Iterator> iterator() { + return Arrays.asList(vertices).iterator(); + } + public static class Point> implements Comparable> { + final T label; + final double x; + final double y; + public Point(T label, double x, double y) { + this.label = label; + this.x = x; + this.y = y; + } + @Override public String toString() { + return String.valueOf(label); + } + @Override public int compareTo(Point o) { + return label.compareTo(o.label); + } + } +} + +abstract class IndexedGraph implements Graph { + final double[][] distance; + public IndexedGraph(double[][] distance) { + this.distance = distance; + } + @Override public T startVertex() { + return getVertex(0); + } + @Override public double distance(T from, T to) { + return distance[getIndex(from)][getIndex(to)]; + } + @Override public Iterator iterator() { + return IntStream.range(0, getVertexCount()).mapToObj(this::getVertex).iterator(); + } + private int getVertexCount() { + return distance.length; + } + protected abstract T getVertex(int index); + protected abstract int getIndex(T vertex); +} + +class CharacterGraph extends IndexedGraph { + private final char base; + public CharacterGraph(double[][] distance, char base) { + super(distance); + this.base = base; + } + @Override protected Character getVertex(int index) { + return (char)(base + index); + } + @Override protected int getIndex(Character vertex) { + return vertex - base; + } +} + +interface Crash { + double INF = Double.POSITIVE_INFINITY; + void run(Graph graph); + + // From video, solution: 0->1->3->2->0 costing 21 + CharacterGraph VIDEO = new CharacterGraph(new double[][] { + {0, 1, 15, 6}, + {2, 0, 7, 3}, + {9, 6, 0, 12}, + {10, 4, 8, 0}, + }, '0'); + + // From comments, solution: A->C->E->D->B->A costing 21 + CharacterGraph COMMENT = new CharacterGraph(new double[][] { + {0, 3, 3, 1, INF}, + {3, 0, 8, 5, INF}, + {3, 8, 0, 1, 6}, + {1, 5, 1, 0, 4}, + {INF, INF, 6, 4, 0}, + }, 'A'); + + // From http://lcm.csa.iisc.ernet.in/dsa/node186.html, solution a->c->d->e->f->b->a 48.39 + GeometricGraph CARTESIAN = new GeometricGraph<>( + new GeometricGraph.Point<>('a', 0, 0), + new GeometricGraph.Point<>('b', 4, 3), + new GeometricGraph.Point<>('c', 1, 7), + new GeometricGraph.Point<>('d', 15, 7), + new GeometricGraph.Point<>('e', 15, 4), + new GeometricGraph.Point<>('f', 18, 0) + ); + + // http://www.geomidpoint.com/random/ whole world 100 points + GeometricGraph GEO = new GeometricGraph<>( + new GeometricGraph.Point<>(1, 41.75887603, 45.54442576), + new GeometricGraph.Point<>(2, 25.95582633, 53.31372621), + new GeometricGraph.Point<>(3, 27.10968149, -148.3088281), + new GeometricGraph.Point<>(4, 47.89312627, 63.62800849), + new GeometricGraph.Point<>(5, -39.63985521, 22.72245952), + new GeometricGraph.Point<>(6, 10.75270177, 172.5620158), + new GeometricGraph.Point<>(7, -5.22786075, 174.0175703), + new GeometricGraph.Point<>(8, 6.09021552, -174.842083), + new GeometricGraph.Point<>(9, -41.93929433, -151.4679823), + new GeometricGraph.Point<>(10, 23.76929542, 52.02191021), + new GeometricGraph.Point<>(11, -27.07564288, -65.97458804), + new GeometricGraph.Point<>(12, -44.69115169, 3.9545051), + new GeometricGraph.Point<>(13, -5.43915001, -67.03701528), + new GeometricGraph.Point<>(14, -46.80168575, 167.7479893), + new GeometricGraph.Point<>(15, 3.37026877, -112.5740888), + new GeometricGraph.Point<>(16, 72.28180933, -29.27517743), + new GeometricGraph.Point<>(17, -42.08042944, -45.20059984), + new GeometricGraph.Point<>(18, -5.94878325, 65.81227912), + new GeometricGraph.Point<>(19, 0.82655482, -137.5756048), + new GeometricGraph.Point<>(20, -1.89649258, -34.85895025), + new GeometricGraph.Point<>(21, -8.41830692, 72.91705955), + new GeometricGraph.Point<>(22, -67.12475398, -30.98024614), + new GeometricGraph.Point<>(23, 3.27537627, -101.5926056), + new GeometricGraph.Point<>(24, 28.12320278, 171.0993409), + new GeometricGraph.Point<>(25, 43.81836686, 153.6367713), + new GeometricGraph.Point<>(26, -30.26453996, 125.4817181), + new GeometricGraph.Point<>(27, 30.42399561, 140.6854059), + new GeometricGraph.Point<>(28, 51.15497569, -118.603574), + new GeometricGraph.Point<>(29, -26.11317488, 165.3413163), + new GeometricGraph.Point<>(30, 17.3884151, 109.0310505), + new GeometricGraph.Point<>(31, -53.28586665, 113.3310133), + new GeometricGraph.Point<>(32, -36.91984178, 17.53340885), + new GeometricGraph.Point<>(33, -49.45998685, 111.9311892), + new GeometricGraph.Point<>(34, -63.1554812, 79.70629564), + new GeometricGraph.Point<>(35, 28.82084009, -9.14338737), + new GeometricGraph.Point<>(36, 37.52058234, -0.32285569), + new GeometricGraph.Point<>(37, 23.58437569, -138.7499972), + new GeometricGraph.Point<>(38, -28.07522086, -175.3760246), + new GeometricGraph.Point<>(39, -63.57013678, -100.3303656), + new GeometricGraph.Point<>(40, 16.2360492, -7.04890614), + new GeometricGraph.Point<>(41, 32.50586034, -93.26947618), + new GeometricGraph.Point<>(42, 0.37760791, 114.3663184), + new GeometricGraph.Point<>(43, -54.95460861, 173.9221499), + new GeometricGraph.Point<>(44, -62.88777314, 11.02357861), + new GeometricGraph.Point<>(45, -0.39552891, -10.24023055), + new GeometricGraph.Point<>(46, -32.82228853, 2.49278472), + new GeometricGraph.Point<>(47, -21.93177958, 104.425205), + new GeometricGraph.Point<>(48, 40.66726414, 1.38813168), + new GeometricGraph.Point<>(49, -10.17461981, -147.9987545), + new GeometricGraph.Point<>(50, -14.10034262, 115.3193397), + new GeometricGraph.Point<>(51, -60.18635059, -77.7990411) + ); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/PolyMethodCallArgumentPassedToVarargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/PolyMethodCallArgumentPassedToVarargs.java new file mode 100644 index 000000000000..15550dab459d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/performance/PolyMethodCallArgumentPassedToVarargs.java @@ -0,0 +1,71 @@ +class GeometricGraph> { + + public static > GeometricGraph createGraph(Point... points) { + return null; + } +} +class Point> implements Comparable> { + @Override public int compareTo(Point o) { + return 0; + } + + static > Point create(M m) { + return null; + } +} + +class Graph { + + GeometricGraph GEO = GeometricGraph.createGraph( + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381), + Point.create(49), + Point.create(73), + Point.create(16), + Point.create(21), + Point.create(381), + Point.create(49), + Point.create(381) + ); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferencePerformanceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferencePerformanceTest.java new file mode 100644 index 000000000000..5ba7c67c169f --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/InferencePerformanceTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.lambda; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.PlatformTestUtil; +import org.jetbrains.annotations.NonNls; + +public class InferencePerformanceTest extends LightDaemonAnalyzerTestCase { + @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/performance"; + + public void testPolyMethodCallArgumentPassedToVarargs() throws Exception { + PlatformTestUtil.startPerformanceTest("50 poly method calls passed to Arrays.asList", 10000, this::doTest).useLegacyScaling().assertTiming(); + } + + public void testDiamondConstructorCallPassedToVarargs() throws Exception { + PlatformTestUtil.startPerformanceTest("50 diamond constructor calls passed to Arrays.asList", 10000, this::doTest).useLegacyScaling().assertTiming(); + } + + private void doTest() { + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); + doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java index 41d03b6e7d23..9d53c201f6a6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java @@ -21,7 +21,6 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.PlatformTestUtil; -import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NonNls; public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase { @@ -98,21 +97,11 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase { } public void testManyOverloadsWithVarargs() throws Exception { - PlatformTestUtil.startPerformanceTest("Overload resolution with 14 overloads", 20000, new ThrowableRunnable() { - @Override - public void run() throws Throwable { - doTest(false); - } - }).useLegacyScaling().assertTiming(); + PlatformTestUtil.startPerformanceTest("Overload resolution with 14 overloads", 10000, () -> doTest(false)).useLegacyScaling().assertTiming(); } public void testConstructorOverloadsWithDiamonds() throws Exception { - PlatformTestUtil.startPerformanceTest("Overload resolution with chain constructor calls with diamonds", 10000, new ThrowableRunnable() { - @Override - public void run() throws Throwable { - doTest(false); - } - }).useLegacyScaling().assertTiming(); + PlatformTestUtil.startPerformanceTest("Overload resolution with chain constructor calls with diamonds", 5000, () -> doTest(false)).useLegacyScaling().assertTiming(); } public void testMultipleOverloadsWithNestedGeneric() throws Exception {