mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
new inference: provide diagnostics on failed inference (checked exceptions)
This commit is contained in:
+18
-4
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
|
||||
@@ -67,10 +68,15 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai
|
||||
}
|
||||
if (myExpression instanceof PsiLambdaExpression || myExpression instanceof PsiMethodReferenceExpression) {
|
||||
if (!LambdaUtil.isFunctionalType(myT)) {
|
||||
session.registerIncompatibleErrorMessage(myT.getPresentableText() + " is not a functional interface");
|
||||
return false;
|
||||
}
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(myT);
|
||||
|
||||
final PsiType groundTargetType = myExpression instanceof PsiLambdaExpression ? FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT, (PsiLambdaExpression)myExpression, false)
|
||||
: FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(groundTargetType);
|
||||
if (interfaceMethod == null) {
|
||||
session.registerIncompatibleErrorMessage("No valid function type can be found for " + myT.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -78,20 +84,28 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai
|
||||
if (myExpression instanceof PsiLambdaExpression && !((PsiLambdaExpression)myExpression).hasFormalParameterTypes() ||
|
||||
myExpression instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression)myExpression).isExact()) {
|
||||
for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
|
||||
if (!session.isProperType(substitutor.substitute(parameter.getType()))) return false;
|
||||
final PsiType type = session.substituteWithInferenceVariables(substitutor.substitute(parameter.getType()));
|
||||
if (!session.isProperType(type)) {
|
||||
session.registerIncompatibleErrorMessage("Parameter type is not yet inferred: " + type.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PsiType returnType = interfaceMethod.getReturnType();
|
||||
if (myExpression instanceof PsiLambdaExpression || !((PsiMethodReferenceExpression)myExpression).isExact()) {
|
||||
if (!session.isProperType(substitutor.substitute(returnType))) return false;
|
||||
final PsiType type = session.substituteWithInferenceVariables(substitutor.substitute(returnType));
|
||||
if (!session.isProperType(type)) {
|
||||
session.registerIncompatibleErrorMessage("Return type is not yet inferred: " + type.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final List<PsiType>
|
||||
expectedThrownTypes = ContainerUtil.map(interfaceMethod.getThrowsList().getReferencedTypes(), new Function<PsiType, PsiType>() {
|
||||
@Override
|
||||
public PsiType fun(PsiType type) {
|
||||
return substitutor.substitute(type);
|
||||
return session.substituteWithInferenceVariables(substitutor.substitute(type));
|
||||
}
|
||||
});
|
||||
final List<PsiType> expectedNonProperThrownTypes = new ArrayList<PsiType>();
|
||||
|
||||
+12
-3
@@ -1,5 +1,6 @@
|
||||
package com.intellij.psi.impl.source.resolve.graphInference.constraints;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
@@ -13,6 +14,7 @@ import java.util.List;
|
||||
* User: anna
|
||||
*/
|
||||
public class LambdaExpressionCompatibilityConstraint implements ConstraintFormula {
|
||||
private static final Logger LOG = Logger.getInstance("#" + LambdaExpressionCompatibilityConstraint.class.getName());
|
||||
private final PsiLambdaExpression myExpression;
|
||||
private PsiType myT;
|
||||
|
||||
@@ -32,6 +34,7 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(groundTargetType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (interfaceMethod == null) {
|
||||
session.registerIncompatibleErrorMessage("No valid function type can be found for " + myT.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
|
||||
@@ -39,16 +42,20 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
|
||||
final PsiParameter[] lambdaParameters = myExpression.getParameterList().getParameters();
|
||||
if (lambdaParameters.length != parameters.length) {
|
||||
session.registerIncompatibleErrorMessage("Incompatible parameter types in lambda expression");
|
||||
return false;
|
||||
}
|
||||
if (myExpression.hasFormalParameterTypes()) {
|
||||
for (int i = 0; i < lambdaParameters.length; i++) {
|
||||
constraints.add(new TypeEqualityConstraint(lambdaParameters[i].getType(), substitutor.substitute(parameters[i].getType())));
|
||||
constraints.add(new TypeEqualityConstraint(lambdaParameters[i].getType(), session.substituteWithInferenceVariables(substitutor.substitute(parameters[i].getType()))));
|
||||
}
|
||||
constraints.add(new StrictSubtypingConstraint(myT, groundTargetType));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (!session.isProperType(session.substituteWithInferenceVariables(substitutor.substitute(parameter.getType())))) {
|
||||
final PsiType type = session.substituteWithInferenceVariables(substitutor.substitute(parameter.getType()));
|
||||
if (!session.isProperType(type)) {
|
||||
//session.registerIncompatibleErrorMessage("Parameter type in not yet inferred: " + type.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -60,11 +67,13 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
final PsiElement lambdaBody = myExpression.getBody();
|
||||
if (returnType.equals(PsiType.VOID)) {
|
||||
if (!(lambdaBody instanceof PsiCodeBlock && myExpression.isVoidCompatible()) && !LambdaUtil.isExpressionStatementExpression(lambdaBody)) {
|
||||
session.registerIncompatibleErrorMessage("Incompatible types: expected void but the lambda body is neither a statement expression nor a void-compatible block");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lambdaBody instanceof PsiCodeBlock && !myExpression.isValueCompatible()) {
|
||||
session.registerIncompatibleErrorMessage("Incompatible types: expected not void but the lambda body is a block that is not value-compatible");
|
||||
return false;
|
||||
}
|
||||
InferenceSession callsession = session.getInferenceSessionContainer().findNestedCallSession(myExpression, session);
|
||||
|
||||
+10
-2
@@ -57,6 +57,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(groundTargetType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult);
|
||||
if (interfaceMethod == null) {
|
||||
session.registerIncompatibleErrorMessage("No valid function type can be found for " + myT.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,16 +98,20 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i - 1].getType())),
|
||||
signature.getParameterTypes()[i]));
|
||||
}
|
||||
} else if (targetParameters.length == parameters.length) {
|
||||
}
|
||||
else if (targetParameters.length == parameters.length) {
|
||||
for (int i = 0; i < targetParameters.length; i++) {
|
||||
constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i].getType())),
|
||||
signature.getParameterTypes()[i]));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
session.registerIncompatibleErrorMessage("Incompatible parameter types in method reference expression");
|
||||
return false;
|
||||
}
|
||||
if (!PsiType.VOID.equals(returnType) && returnType != null) {
|
||||
if (PsiType.VOID.equals(applicableMethodReturnType)) {
|
||||
session.registerIncompatibleErrorMessage("Incompatible types: expected not void but compile-time declaration for the method reference has void return type");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -129,6 +134,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
|
||||
for (PsiType paramType : signature.getParameterTypes()) {
|
||||
if (!session.isProperType(paramType)) {
|
||||
//session.registerIncompatibleErrorMessage("Parameter type in not yet inferred: " + type.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +152,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
final PsiElement element = resolve.getElement();
|
||||
if (element == null) {
|
||||
session.registerIncompatibleErrorMessage("No compile-time declaration for the method reference is found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -187,6 +194,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
}
|
||||
|
||||
if (PsiType.VOID.equals(referencedMethodReturnType)) {
|
||||
session.registerIncompatibleErrorMessage("Incompatible types: expected not void but compile-time declaration for the method reference has void return type");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ class Test5 {
|
||||
static <T> void bar(I<T> i){}
|
||||
|
||||
{
|
||||
bar(() -> <error descr="Bad return type in lambda expression: <null> cannot be converted to void">null</error>);
|
||||
bar(<error descr="Incompatible parameter types in lambda expression">() -> null</error>);
|
||||
}
|
||||
}
|
||||
class Test6 {
|
||||
@@ -31,7 +31,7 @@ class Test6 {
|
||||
static <T> void bar(I<T> i){}
|
||||
|
||||
{
|
||||
bar(() -> <error descr="Bad return type in lambda expression: <null> cannot be converted to void">null</error>);
|
||||
bar(<error descr="Incompatible types: expected void but the lambda body is neither a statement expression nor a void-compatible block">() -> null</error>);
|
||||
bar(() -> {});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user