mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
new inference: well formed check
This commit is contained in:
+2
-75
@@ -234,7 +234,7 @@ public class GenericsHighlightUtil {
|
||||
final PsiClass referenceClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null;
|
||||
final PsiType psiType = substitutor.substitute(classParameter);
|
||||
if (psiType instanceof PsiClassType && !(PsiUtil.resolveClassInType(psiType) instanceof PsiTypeParameter)) {
|
||||
if (checkNotInBounds(type, psiType, referenceParameterList)) {
|
||||
if (GenericsUtil.checkNotInBounds(type, psiType, referenceParameterList)) {
|
||||
final String description = "Actual type argument and inferred type contradict each other";
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement2Highlight).descriptionAndTooltip(description).create();
|
||||
}
|
||||
@@ -243,7 +243,7 @@ public class GenericsHighlightUtil {
|
||||
final PsiClassType[] bounds = classParameter.getSuperTypes();
|
||||
for (PsiClassType type1 : bounds) {
|
||||
PsiType bound = substitutor.substitute(type1);
|
||||
if (!bound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && checkNotInBounds(type, bound, referenceParameterList)) {
|
||||
if (!bound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && GenericsUtil.checkNotInBounds(type, bound, referenceParameterList)) {
|
||||
PsiClass boundClass = bound instanceof PsiClassType ? ((PsiClassType)bound).resolve() : null;
|
||||
|
||||
@NonNls final String messageKey = boundClass == null || referenceClass == null || referenceClass.isInterface() == boundClass.isInterface()
|
||||
@@ -267,79 +267,6 @@ public class GenericsHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean checkNotInBounds(PsiType type, PsiType bound, PsiReferenceParameterList referenceParameterList) {
|
||||
if (type instanceof PsiClassType) {
|
||||
return checkNotAssignable(bound, type, allowUncheckedConversions((PsiClassType)type, referenceParameterList));
|
||||
}
|
||||
if (type instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)type).isExtends()) {
|
||||
return checkExtendsWildcardCaptureFailure((PsiWildcardType)type, bound);
|
||||
}
|
||||
else if (((PsiWildcardType)type).isSuper()) {
|
||||
final PsiType superBound = ((PsiWildcardType)type).getSuperBound();
|
||||
if (PsiUtil.resolveClassInType(superBound) instanceof PsiTypeParameter) return TypesDistinctProver.provablyDistinct(type, bound);
|
||||
return checkNotAssignable(bound, superBound, false);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PsiArrayType) {
|
||||
return checkNotAssignable(bound, type, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//JLS 5.1.10
|
||||
private static boolean checkExtendsWildcardCaptureFailure(PsiWildcardType type, PsiType bound) {
|
||||
LOG.assertTrue(type.isExtends());
|
||||
final PsiType extendsBound = type.getExtendsBound();
|
||||
PsiType boundBound = bound;
|
||||
if (bound instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)bound).isBounded()) {
|
||||
boundBound = ((PsiWildcardType)bound).isSuper()
|
||||
? ((PsiWildcardType)bound).getSuperBound()
|
||||
: ((PsiWildcardType)bound).getExtendsBound();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !TypeConversionUtil.areTypesConvertible(boundBound, extendsBound) &&
|
||||
!TypeConversionUtil.areTypesConvertible(extendsBound, boundBound);
|
||||
}
|
||||
|
||||
private static boolean checkNotAssignable(final PsiType bound,
|
||||
final PsiType type,
|
||||
final boolean allowUncheckedConversion) {
|
||||
if (bound instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)bound).isBounded()) {
|
||||
final PsiType boundBound = ((PsiWildcardType)bound).isExtends()
|
||||
? ((PsiWildcardType)bound).getExtendsBound()
|
||||
: ((PsiWildcardType)bound).getSuperBound();
|
||||
return !TypeConversionUtil.isAssignable(boundBound, type, allowUncheckedConversion);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !TypeConversionUtil.isAssignable(bound, type, allowUncheckedConversion);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean allowUncheckedConversions(PsiClassType type, PsiReferenceParameterList referenceParameterList) {
|
||||
final PsiClass psiClass = type.resolve();
|
||||
if (psiClass != null) {
|
||||
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(psiClass)) {
|
||||
if (parameter.getExtendsListTypes().length != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (psiClass instanceof PsiTypeParameter && psiClass.getExtendsListTypes().length != 0) return false;
|
||||
}
|
||||
if (!type.isRaw()) return true;
|
||||
//allow unchecked conversions in method calls but not in type declaration
|
||||
return referenceParameterList.getParent() instanceof PsiReferenceExpression;
|
||||
}
|
||||
|
||||
private static String typeParameterListOwnerDescription(final PsiTypeParameterListOwner typeParameterListOwner) {
|
||||
if (typeParameterListOwner instanceof PsiClass) {
|
||||
return HighlightUtil.formatClass((PsiClass)typeParameterListOwner);
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.psi.util.TypesDistinctProver;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -495,4 +496,81 @@ public class GenericsUtil {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public static boolean checkNotInBounds(PsiType type, PsiType bound, PsiReferenceParameterList referenceParameterList) {
|
||||
//allow unchecked conversions in method calls but not in type declaration
|
||||
return checkNotInBounds(type, bound, referenceParameterList.getParent() instanceof PsiReferenceExpression);
|
||||
}
|
||||
|
||||
public static boolean checkNotInBounds(PsiType type, PsiType bound, boolean uncheckedConversionByDefault) {
|
||||
if (type instanceof PsiClassType) {
|
||||
return checkNotAssignable(bound, type, allowUncheckedConversions((PsiClassType)type, uncheckedConversionByDefault));
|
||||
}
|
||||
if (type instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)type).isExtends()) {
|
||||
return checkExtendsWildcardCaptureFailure((PsiWildcardType)type, bound);
|
||||
}
|
||||
else if (((PsiWildcardType)type).isSuper()) {
|
||||
final PsiType superBound = ((PsiWildcardType)type).getSuperBound();
|
||||
if (PsiUtil.resolveClassInType(superBound) instanceof PsiTypeParameter) return TypesDistinctProver.provablyDistinct(type, bound);
|
||||
return checkNotAssignable(bound, superBound, false);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PsiArrayType) {
|
||||
return checkNotAssignable(bound, type, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//JLS 5.1.10
|
||||
private static boolean checkExtendsWildcardCaptureFailure(PsiWildcardType type, PsiType bound) {
|
||||
LOG.assertTrue(type.isExtends());
|
||||
final PsiType extendsBound = type.getExtendsBound();
|
||||
PsiType boundBound = bound;
|
||||
if (bound instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)bound).isBounded()) {
|
||||
boundBound = ((PsiWildcardType)bound).isSuper()
|
||||
? ((PsiWildcardType)bound).getSuperBound()
|
||||
: ((PsiWildcardType)bound).getExtendsBound();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !TypeConversionUtil.areTypesConvertible(boundBound, extendsBound) &&
|
||||
!TypeConversionUtil.areTypesConvertible(extendsBound, boundBound);
|
||||
}
|
||||
|
||||
private static boolean checkNotAssignable(final PsiType bound,
|
||||
final PsiType type,
|
||||
final boolean allowUncheckedConversion) {
|
||||
if (bound instanceof PsiWildcardType) {
|
||||
if (((PsiWildcardType)bound).isBounded()) {
|
||||
final PsiType boundBound = ((PsiWildcardType)bound).isExtends()
|
||||
? ((PsiWildcardType)bound).getExtendsBound()
|
||||
: ((PsiWildcardType)bound).getSuperBound();
|
||||
return !TypeConversionUtil.isAssignable(boundBound, type, allowUncheckedConversion);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return !TypeConversionUtil.isAssignable(bound, type, allowUncheckedConversion);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean allowUncheckedConversions(PsiClassType type, boolean uncheckedConversionByDefault) {
|
||||
final PsiClass psiClass = type.resolve();
|
||||
if (psiClass != null) {
|
||||
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(psiClass)) {
|
||||
if (parameter.getExtendsListTypes().length != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (psiClass instanceof PsiTypeParameter && psiClass.getExtendsListTypes().length != 0) return false;
|
||||
}
|
||||
if (!type.isRaw()) return true;
|
||||
return uncheckedConversionByDefault;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-4
@@ -102,8 +102,7 @@ public class FunctionalInterfaceParameterizationUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = session.resolveBounds(true);
|
||||
|
||||
session.resolveBounds(false);
|
||||
final PsiType[] newTypeParameters = new PsiType[parameters.length];
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
PsiTypeParameter typeParameter = typeParameters[i];
|
||||
@@ -118,8 +117,7 @@ public class FunctionalInterfaceParameterizationUtil {
|
||||
|
||||
final PsiClassType parameterization = elementFactory.createType(psiClass, newTypeParameters);
|
||||
|
||||
if (//todo !TypeConversionUtil.isAssignable(psiClassType, parameterization) ||
|
||||
!GenericsUtil.isTypeArgumentsApplicable(typeParameters, PsiSubstitutor.EMPTY.putAll(psiClass, newTypeParameters), expr)) {
|
||||
if (!isWellFormed(psiClass, typeParameters, newTypeParameters)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -132,6 +130,18 @@ public class FunctionalInterfaceParameterizationUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isWellFormed(PsiClass psiClass, PsiTypeParameter[] typeParameters, PsiType[] newTypeParameters) {
|
||||
final PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.putAll(psiClass, newTypeParameters);
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
for (PsiClassType bound : typeParameters[i].getExtendsListTypes()) {
|
||||
if (GenericsUtil.checkNotInBounds(newTypeParameters[i], substitutor.substitute(bound), false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
The function type of a parameterized functional interface, F<A1...An>, where one or more of A1...An is a wildcard, is the function type of the non-wildcard parameterization of F, F<T1...Tn> determined as follows.
|
||||
Let P1, ..., Pn be the type parameters of F and B1, ..., Bn be the corresponding bounds. For all i, 1 ≤ i ≤ n, Ti is derived according to the form of Ai:
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ class Test {
|
||||
void foo(I<? extends String, ? extends List<? extends String>> fip) { }
|
||||
|
||||
void test() {
|
||||
foo(<error descr="Cannot infer functional interface type">(ArrayList<? extends String> p) -> p.get(0)</error>);
|
||||
foo<error descr="'foo(Test.I<? extends java.lang.String,? extends java.util.List<? extends java.lang.String>>)' in 'Test' cannot be applied to '(<lambda expression>)'">((ArrayList<? extends String> p) -> p.get(0))</error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user