TypeParameter inferred types check unification

This commit is contained in:
Anna Kozlova
2013-08-16 11:28:51 +04:00
parent 731ac987a0
commit e1e583734a
3 changed files with 30 additions and 47 deletions
@@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -59,49 +60,24 @@ public class GenericsHighlightUtil {
public static HighlightInfo checkInferredTypeArguments(PsiMethod genericMethod,
PsiMethodCallExpression call,
PsiSubstitutor substitutor) {
PsiTypeParameter[] typeParameters = genericMethod.getTypeParameters();
for (PsiTypeParameter typeParameter : typeParameters) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return null;
substituted = PsiUtil.captureToplevelWildcards(substituted, call);
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
for (PsiClassType type : extendsTypes) {
PsiType extendsType = substitutor.substitute(type);
if (substituted instanceof PsiWildcardType) {
if (((PsiWildcardType)substituted).isSuper()) {
continue;
}
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(extendsBound))) {
if (extendsBound instanceof PsiClassType) {
PsiType[] parameters = ((PsiClassType)extendsBound).getParameters();
if (parameters.length == 1) {
PsiType argType = parameters[0];
if (argType instanceof PsiCapturedWildcardType) {
argType = ((PsiCapturedWildcardType)argType).getWildcard();
}
if (argType instanceof PsiWildcardType && !((PsiWildcardType)argType).isBounded()) continue;
}
}
}
}
if (!TypeConversionUtil.isAssignable(extendsType, substituted, false)) {
PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType)extendsType).resolve() : null;
final Pair<PsiTypeParameter, PsiType> inferredTypeArgument =
GenericsUtil.findTypeParameterWithBoundError(genericMethod.getTypeParameters(), substitutor, call, false);
if (inferredTypeArgument != null) {
final PsiType extendsType = inferredTypeArgument.second;
final PsiTypeParameter typeParameter = inferredTypeArgument.first;
PsiClass boundClass = extendsType instanceof PsiClassType ? ((PsiClassType)extendsType).resolve() : null;
@NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface()
? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend"
: "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement";
@NonNls String messageKey = boundClass == null || typeParameter.isInterface() == boundClass.isInterface()
? "generics.inferred.type.for.type.parameter.is.not.within.its.bound.extend"
: "generics.inferred.type.for.type.parameter.is.not.within.its.bound.implement";
String description = JavaErrorMessages.message(
messageKey,
HighlightUtil.formatClass(typeParameter),
JavaHighlightUtil.formatType(extendsType),
JavaHighlightUtil.formatType(substituted)
);
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(call).descriptionAndTooltip(description).create();
}
}
String description = JavaErrorMessages.message(
messageKey,
HighlightUtil.formatClass(typeParameter),
JavaHighlightUtil.formatType(extendsType),
JavaHighlightUtil.formatType(substitutor.substitute(typeParameter))
);
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(call).descriptionAndTooltip(description).create();
}
return null;
@@ -249,10 +249,17 @@ public class GenericsUtil {
final PsiSubstitutor substitutor,
final PsiElement context,
final boolean allowUncheckedConversion) {
return findTypeParameterWithBoundError(typeParams, substitutor, context, allowUncheckedConversion) == null;
}
public static Pair<PsiTypeParameter, PsiType> findTypeParameterWithBoundError(final PsiTypeParameter[] typeParams,
final PsiSubstitutor substitutor,
final PsiElement context,
final boolean allowUncheckedConversion) {
nextTypeParam:
for (PsiTypeParameter typeParameter : typeParams) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return true;
if (substituted == null) return null;
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
@@ -263,7 +270,7 @@ public class GenericsUtil {
continue;
}
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(extendsBound))) {
if (Comparing.equal(TypeConversionUtil.erasure(extendsType), TypeConversionUtil.erasure(extendsBound))) {
if (extendsBound instanceof PsiClassType) {
if (acceptExtendsBound((PsiClassType)extendsBound, 0)) continue;
} else if (extendsBound instanceof PsiIntersectionType) {
@@ -275,12 +282,12 @@ public class GenericsUtil {
}
}
}
if (!TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
return false;
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
return Pair.create(typeParameter, extendsType);
}
}
}
return true;
return null;
}
private static boolean acceptExtendsBound(PsiClassType extendsBound, int depth) {
@@ -18,7 +18,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
list.add(t1);
SortTest<?> t2 = new SortTest<Integer>(0);
list.add(t2);
<error descr="Inferred type 'SortTest<capture<?>>' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super SortTest<?>>'">Collections.sort(list)</error>;
<error descr="Inferred type 'SortTest<?>' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super SortTest<?>>'">Collections.sort(list)</error>;
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
//this should be OK