mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
inference: check glb conflicts after flatten in intersection type(IDEA-181017)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {}
|
||||
}
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user