mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
new inference: register incompatible message if inference fails (IDEA-131882; to be extended); filter out candidates if inference had failed for them
This commit is contained in:
@@ -372,10 +372,7 @@ public class InferenceSession {
|
||||
}
|
||||
mySiteSubstitutor = mySiteSubstitutor.put(param, mapping);
|
||||
}
|
||||
} else {
|
||||
return prepareSubstitution();
|
||||
}
|
||||
|
||||
return prepareSubstitution();
|
||||
}
|
||||
finally {
|
||||
@@ -1111,16 +1108,30 @@ public class InferenceSession {
|
||||
|
||||
private PsiType registerIncompatibleErrorMessage(InferenceVariable var, @NotNull String incompatibleBoundsMessage) {
|
||||
if (var.getCallContext() == myContext) {
|
||||
if (myErrorMessages == null) {
|
||||
myErrorMessages = new ArrayList<String>();
|
||||
}
|
||||
if (!myErrorMessages.contains(incompatibleBoundsMessage)) {
|
||||
myErrorMessages.add(incompatibleBoundsMessage);
|
||||
}
|
||||
registerIncompatibleErrorMessage(incompatibleBoundsMessage);
|
||||
}
|
||||
return PsiType.NULL;
|
||||
}
|
||||
|
||||
public void registerIncompatibleErrorMessage(Collection<InferenceVariable> variables, String incompatibleTypesMessage) {
|
||||
final String variablesEnumeration = StringUtil.join(variables, new Function<InferenceVariable, String>() {
|
||||
@Override
|
||||
public String fun(InferenceVariable variable) {
|
||||
return variable.getName();
|
||||
}
|
||||
}, ", ");
|
||||
registerIncompatibleErrorMessage("no instance(s) of type variable(s) " + variablesEnumeration + " exist so that " + incompatibleTypesMessage);
|
||||
}
|
||||
|
||||
public void registerIncompatibleErrorMessage(@NotNull String incompatibleBoundsMessage) {
|
||||
if (myErrorMessages == null) {
|
||||
myErrorMessages = new ArrayList<String>();
|
||||
}
|
||||
if (!myErrorMessages.contains(incompatibleBoundsMessage)) {
|
||||
myErrorMessages.add(incompatibleBoundsMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private String incompatibleBoundsMessage(final InferenceVariable var,
|
||||
final PsiSubstitutor substitutor,
|
||||
final InferenceBound lowBound,
|
||||
@@ -1778,4 +1789,8 @@ public class InferenceSession {
|
||||
public void registerSiteSubstitutor(PsiSubstitutor substitutor) {
|
||||
mySiteSubstitutor = mySiteSubstitutor.putAll(substitutor);
|
||||
}
|
||||
|
||||
public List<String> getIncompatibleErrorMessages() {
|
||||
return myErrorMessages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,17 +142,26 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
callSession.initExpressionConstraints(parameters, args, expression, method, InferenceSession
|
||||
.chooseVarargsMode(candidateProperties, resolveResult));
|
||||
}
|
||||
final boolean accepted = callSession.repeatInferencePhases(true);
|
||||
if (!accepted) {
|
||||
return null;
|
||||
}
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
if (callSession.repeatInferencePhases(true)) {
|
||||
return callSession;
|
||||
|
||||
if (PsiType.VOID.equals(targetType)) {
|
||||
return callSession;
|
||||
}
|
||||
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
if (callSession.repeatInferencePhases(true)) {
|
||||
return callSession;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
|
||||
//copy incompatible message if any
|
||||
final List<String> messages = callSession.getIncompatibleErrorMessages();
|
||||
if (messages != null) {
|
||||
for (String message : messages) {
|
||||
session.registerIncompatibleErrorMessage(message);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return session;
|
||||
|
||||
@@ -22,6 +22,7 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
@Override
|
||||
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
if (!LambdaUtil.isFunctionalType(myT)) {
|
||||
session.registerIncompatibleErrorMessage(myT.getPresentableText() + " is not a functional interface");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
@Override
|
||||
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
if (!LambdaUtil.isFunctionalType(myT)) {
|
||||
session.registerIncompatibleErrorMessage(myT.getPresentableText() + " is not a functional interface");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -45,12 +46,21 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
|
||||
|
||||
@Override
|
||||
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
if (session.isProperType(myS) && session.isProperType(myT)) {
|
||||
final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
|
||||
if (!session.collectDependencies(myS, dependencies) && !session.collectDependencies(myT, dependencies)) {
|
||||
if (myT == null) return myS == null || myS.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
|
||||
if (myS == null) return true;
|
||||
return TypeConversionUtil.isAssignable(myT, myS);
|
||||
}
|
||||
|
||||
final boolean reduceResult = nonProperReduce(session, constraints);
|
||||
if (!reduceResult) {
|
||||
session.registerIncompatibleErrorMessage(dependencies, myS.getPresentableText() + " conforms to " + myT.getPresentableText());
|
||||
}
|
||||
return reduceResult;
|
||||
}
|
||||
|
||||
private boolean nonProperReduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
if (PsiType.NULL.equals(myT) || myT == null) return false;
|
||||
if (PsiType.NULL.equals(myS) || myS == null || myT.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return true;
|
||||
|
||||
|
||||
@@ -63,6 +63,14 @@ public class SubtypingConstraint implements ConstraintFormula {
|
||||
|
||||
@Override
|
||||
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
|
||||
final boolean reduceResult = doReduce(constraints);
|
||||
if (!reduceResult) {
|
||||
session.registerIncompatibleErrorMessage(session.getInferenceVariables(), myS.getPresentableText() + " can be converted to " + myT.getPresentableText());
|
||||
}
|
||||
return reduceResult;
|
||||
}
|
||||
|
||||
private boolean doReduce(List<ConstraintFormula> constraints) {
|
||||
if (myT instanceof PsiWildcardType) {
|
||||
PsiType tBound = ((PsiWildcardType)myT).getBound();
|
||||
if (tBound == null) {
|
||||
|
||||
@@ -109,6 +109,7 @@ public class TypeEqualityConstraint implements ConstraintFormula {
|
||||
return true;
|
||||
}
|
||||
|
||||
session.registerIncompatibleErrorMessage(session.getInferenceVariables(), myS.getPresentableText() + " conforms to " + myT.getPresentableText());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
return key.getSubstitutor(false);
|
||||
}
|
||||
};
|
||||
|
||||
checkInvocationApplicabilityInference(conflicts, map);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
checkSameSignatures(conflicts, map);
|
||||
if (conflicts.size() == 1) return conflicts.get(0);
|
||||
|
||||
@@ -136,6 +140,20 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void checkInvocationApplicabilityInference(@NotNull List<CandidateInfo> conflicts,
|
||||
FactoryMap<MethodCandidateInfo, PsiSubstitutor> map) {
|
||||
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) {
|
||||
CandidateInfo conflict = iterator.next();
|
||||
if (conflict instanceof MethodCandidateInfo) {
|
||||
getSubstitutor((MethodCandidateInfo)conflict, map);
|
||||
final String errorMessage = ((MethodCandidateInfo)conflict).getInferenceErrorMessage();
|
||||
if (errorMessage != null) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkSpecifics(@NotNull List<CandidateInfo> conflicts,
|
||||
@MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Test {
|
||||
{
|
||||
asList(<error descr="Cyclic inference">o -> {}</error>, 1, 2, 3);
|
||||
asList(<error descr="Integer is not a functional interface">o -> {}</error>, 1, 2, 3);
|
||||
asList(<error descr="T is not a functional interface">Test::foo</error>, 1, 2, 3);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user