lambda: do not accept ? as type argument for return value (IDEA-91369)

This commit is contained in:
Anna Kozlova
2012-09-12 00:03:42 +04:00
parent 9ddff21a9c
commit 943d901fff
3 changed files with 58 additions and 3 deletions
@@ -113,13 +113,43 @@ public class LambdaUtil {
@Nullable
public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
if (checkReturnTypeApplicable(resolveResult, aClass)) {
return "No instance of type " + functionalInterfaceType.getPresentableText() + " exists so that lambda expression can be type-checked";
}
return checkInterfaceFunctional(aClass);
}
return null;
}
private static boolean checkReturnTypeApplicable(PsiClassType.ClassResolveResult resolveResult, final PsiClass aClass) {
final MethodSignature methodSignature = getFunction(aClass);
if (methodSignature == null) return false;
for (PsiTypeParameter parameter : aClass.getTypeParameters()) {
if (parameter.getExtendsListTypes().length == 0) continue;
boolean depends = false;
final PsiType substitution = resolveResult.getSubstitutor().substitute(parameter);
if (substitution instanceof PsiWildcardType && !((PsiWildcardType)substitution).isBounded()) {
for (PsiType paramType : methodSignature.getParameterTypes()) {
if (depends(paramType, parameter, new TypeParamsChecker((PsiMethod)null, aClass){
@Override
public boolean startedInference() {
return true;
}
})) {
depends = true;
break;
}
}
if (!depends) return true;
}
}
return false;
}
@Nullable
public static String checkInterfaceFunctional(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
@@ -40,4 +40,26 @@ class Test1 {
}
}</error>;
}
}
class Test2 {
interface X<T extends Number> {
T foo();
}
{
X<?> x = <error descr="No instance of type X<?> exists so that lambda expression can be type-checked">() -> 123</error>;
X<? extends Number> x1 = () -> 123;
}
}
class Test3 {
interface X<T> {
T foo();
}
{
X<?> x = () -> 123;
}
}
@@ -173,7 +173,10 @@ public class ReplaceLambdaWithAnonymousIntention extends Intention {
if (disabled[0]) return false;
}
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
return functionalInterfaceType != null && LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null && LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType);
return functionalInterfaceType != null &&
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null &&
LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType) &&
LambdaUtil.checkInterfaceFunctional(functionalInterfaceType) == null;
}
return false;
}