inference: check glb conflicts after flatten in intersection type(IDEA-181017)

This commit is contained in:
Anna.Kozlova
2017-10-25 17:52:28 +02:00
parent c8f8341d2f
commit a2e13fee96
4 changed files with 56 additions and 23 deletions

View File

@@ -44,28 +44,7 @@ public class InferenceSession {
private static final Key<PsiType> LOWER_BOUND = Key.create("LowBound");
private static final Key<PsiType> UPPER_BOUND = Key.create("UpperBound");
private static final Key<Boolean> ERASED = Key.create("UNCHECKED_CONVERSION");
private static final Function<Pair<PsiType, PsiType>, PsiType> UPPER_BOUND_FUNCTION = new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
if (!isValidGlb(pair.first, pair.second)) return null;
if (!isValidGlb(pair.second, pair.first)) return null;
return GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
}
private boolean isValidGlb(PsiType first, PsiType second) {
if (second instanceof PsiArrayType && TypesDistinctProver.proveArrayTypeDistinct((PsiArrayType)second, first)) {
return false;
}
if (second instanceof PsiCapturedWildcardType && !first.isAssignableFrom(second)) {
final PsiClass conjunct = PsiUtil.resolveClassInType(first);
if (conjunct != null && !conjunct.isInterface() && !(conjunct instanceof PsiTypeParameter) ) {
return false;
}
}
return true;
}
};
private static final Function<Pair<PsiType, PsiType>, PsiType> UPPER_BOUND_FUNCTION = pair -> GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
private static final String EQUALITY_CONSTRAINTS_PRESENTATION = "equality constraints";
private static final String UPPER_BOUNDS_PRESENTATION = "upper bounds";
@@ -1271,6 +1250,9 @@ public class InferenceSession {
//warn if upper bounds has same generic class with different type arguments
conflictingConjunctsMessage = type.getPresentableText(false);
}
else {
conflictingConjunctsMessage = getConjunctsConflict((PsiIntersectionType)type);
}
}
if (conflictingConjunctsMessage != null) {
registerIncompatibleErrorMessage("Type parameter " + var.getParameter().getName() + " has incompatible upper bounds: " + conflictingConjunctsMessage);
@@ -1304,6 +1286,26 @@ public class InferenceSession {
return type;
}
private static String getConjunctsConflict(PsiIntersectionType type) {
PsiType[] conjuncts = type.getConjuncts();
for (int i = 0; i < conjuncts.length; i++) {
PsiClass conjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i]);
for (int i1 = 0; i1 < conjuncts.length; i1++) {
if (i == i1) continue;
PsiClass oppositeConjunct = PsiUtil.resolveClassInClassTypeOnly(conjuncts[i1]);
if (conjunct == null || oppositeConjunct == null) {
if (conjuncts[i] instanceof PsiArrayType &&
TypesDistinctProver.proveArrayTypeDistinct((PsiArrayType)conjuncts[i], conjuncts[i1]) ||
conjuncts[i] instanceof PsiCapturedWildcardType &&
oppositeConjunct != null && !oppositeConjunct.isInterface() && !(oppositeConjunct instanceof PsiTypeParameter)) {
return conjuncts[i].getPresentableText() + " and " + conjuncts[i1].getPresentableText();
}
}
}
}
return null;
}
public String getPresentableText(PsiType psiType) {
final PsiType substituted = myRestoreNameSubstitution.substitute(psiType);
return substituted != null ? substituted.getPresentableText() : null;

View File

@@ -11,6 +11,6 @@ abstract class A1{
abstract <T> T baz(List<? super T> a);
void bar(List<?> x){
String o = <error descr="Incompatible upper bounds: Object, capture of ?, String">baz(x);</error>
String o = <error descr="Type parameter T has incompatible upper bounds: capture of ? and String">baz(x);</error>
}
}

View File

@@ -0,0 +1,30 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
class Test {
private Map<FilterHelper, Integer> extractFilterCounts() {
final Function<FilterData, Integer> count = f -> null;
final Function<? super FilterData, ? extends FilterHelper> mapper = f -> null;
final List<FilterData> rows = Collections.emptyList();
return rows.stream().collect(Collectors.toMap(mapper, count));
}
private class FilterHelper {}
private class FilterData {}
}
class Test1 {
private void extractFilterCounts(final I<Integer> i1,
final I<? super Integer> i2) {
m(i2, i1);
}
private static <T> void m(I<? super T> i1, I<? super T> i2) { }
static class I<T> {}
}

View File

@@ -182,6 +182,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
public void testFreshVariablesDuringApplicabilityCheck() { doTest(); }
public void testPertinentToApplicabilityCheckForBlockLambda() { doTest(); }
public void testCheckGlbConflictsAfterIntersectionTypeCreated() { doTest(); }
public void testRestoreCapturedWildcardsInReturnTypesWhenNoAdditionalConstraintsDetected() { doTest(); }
public void testVarargsMethodPreferred() { doTest(); }