glb: ensure each super class processed once (IDEA-176779)

This commit is contained in:
Anna.Kozlova
2017-10-16 19:50:59 +02:00
parent 465458db4d
commit bffca304b9
3 changed files with 69 additions and 24 deletions

View File

@@ -110,38 +110,46 @@ public class GenericsUtil {
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
PsiClassType[] conjuncts = new PsiClassType[supers.length];
for (int i = 0; i < supers.length; i++) {
PsiClass aSuper = supers[i];
PsiSubstitutor subst1 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, aClass, classResolveResult1.getSubstitutor());
PsiSubstitutor subst2 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, bClass, classResolveResult2.getSubstitutor());
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
Set<Couple<PsiType>> siblings = new HashSet<>();
try {
for (int i = 0; i < supers.length; i++) {
PsiClass aSuper = supers[i];
PsiSubstitutor subst1 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, aClass, classResolveResult1.getSubstitutor());
PsiSubstitutor subst2 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, bClass, classResolveResult2.getSubstitutor());
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
final Couple<PsiType> types = Couple.of(elementFactory.createType(aSuper, subst1), elementFactory.createType(aSuper, subst2));
final Couple<PsiType> types = Couple.of(elementFactory.createType(aSuper, subst1), elementFactory.createType(aSuper, subst2));
boolean skip = compared.contains(types);
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) {
PsiType mapping1 = subst1.substitute(parameter);
PsiType mapping2 = subst2.substitute(parameter);
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) {
PsiType mapping1 = subst1.substitute(parameter);
PsiType mapping2 = subst2.substitute(parameter);
if (mapping1 != null && mapping2 != null) {
if (compared.contains(types)) {
substitutor = substitutor.put(parameter, PsiWildcardType.createUnbounded(manager));
if (mapping1 != null && mapping2 != null) {
if (skip) {
substitutor = substitutor.put(parameter, PsiWildcardType.createUnbounded(manager));
}
else {
compared.add(types);
try {
PsiType argument = getLeastContainingTypeArgument(mapping1, mapping2, compared, manager);
substitutor = substitutor.put(parameter, argument);
}
finally {
siblings.add(types);
}
}
}
else {
compared.add(types);
try {
substitutor = substitutor.put(parameter, getLeastContainingTypeArgument(mapping1, mapping2, compared, manager));
}
finally {
compared.remove(types);
}
substitutor = substitutor.put(parameter, null);
}
}
else {
substitutor = substitutor.put(parameter, null);
}
}
conjuncts[i] = elementFactory.createType(aSuper, substitutor);
conjuncts[i] = elementFactory.createType(aSuper, substitutor);
}
}
finally {
compared.removeAll(siblings);
}
return PsiIntersectionType.createIntersection(conjuncts);

View File

@@ -0,0 +1,33 @@
import java.util.List;
import java.util.stream.Stream;
class LeastUpperBoundTest {
void f(Stream<Klass> klasses) {
klasses.flatMap(d -> concat(Stream.of(d),
d.getMethods().stream(),
d.getMethods().stream()));
}
@SafeVarargs
private static <T> Stream<T> concat(Stream<? extends T>... streams) {
return null;
}
}
interface Node {}
interface A<T extends Node> {}
interface B<T extends Node> {}
interface C<T extends Node> {}
interface D<T extends Node> {}
interface E<T extends Node> {}
interface E1<T extends Node> {}
interface E2<T extends Node> {}
class Klass implements Node, A<Klass>, B<Klass>, C<Klass>, D<Klass>, E<Klass>, E1<Klass> {
public List<Method> getMethods() {
return null;
}
}
class Method implements Node, A<Method>, B<Method>, C<Method>, D<Method>, E<Method>, E1<Method> {}

View File

@@ -32,6 +32,10 @@ public class InferencePerformanceTest extends LightDaemonAnalyzerTestCase {
PlatformTestUtil.startPerformanceTest("50 diamond constructor calls passed to Arrays.asList", 12000, this::doTest).usesAllCPUCores().assertTiming();
}
public void testLeastUpperBoundWithLotsOfSupers() {
PlatformTestUtil.startPerformanceTest("7 unrelated intersection conjuncts", 12000, this::doTest).usesAllCPUCores().assertTiming();
}
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);