inference: skip constraints that depend on ignored constraints

when type of lambda parameter is calculated, the containing lambda doesn't end in the constraints set; if some other constraints depend on it's output variables, inside those constraints e.g. method calls may be cached based on incomplete inference results which would lead to blinking of highlighting
This commit is contained in:
Anna.Kozlova
2018-11-14 15:18:08 +01:00
parent ae72289117
commit c4393bfa0e
3 changed files with 53 additions and 1 deletions
@@ -415,7 +415,14 @@ public class InferenceSession {
if (arg instanceof PsiLambdaExpression && ignoreConstraintTree(ignoredConstraints, arg, parameterType)) {
continue;
}
additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
ExpressionCompatibilityConstraint compatibilityConstraint = new ExpressionCompatibilityConstraint(arg, parameterType);
if (dependsOnIgnoredConstraint(ignoredConstraints, compatibilityConstraint)) {
ignoredConstraints.add(compatibilityConstraint);
continue;
}
additionalConstraints.add(compatibilityConstraint);
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType));
if (arg instanceof PsiCall) {
@@ -437,6 +444,23 @@ public class InferenceSession {
}
}
private boolean dependsOnIgnoredConstraint(Set<ConstraintFormula> ignoredConstraints, ExpressionCompatibilityConstraint compatibilityConstraint) {
if (!ignoredConstraints.isEmpty()) {
Set<InferenceVariable> inputVariables = compatibilityConstraint.getInputVariables(this);
if (inputVariables != null) {
for (ConstraintFormula ignoredConstraint : ignoredConstraints) {
if (ignoredConstraint instanceof InputOutputConstraintFormula) {
Set<InferenceVariable> inputsOfIgnored = ((InputOutputConstraintFormula)ignoredConstraint).getInputVariables(this);
Set<InferenceVariable> outputVariables = ((InputOutputConstraintFormula)ignoredConstraint).getOutputVariables(inputsOfIgnored, this);
if (outputVariables != null && ContainerUtil.intersects(outputVariables, inputVariables)) return true;
}
}
}
}
return false;
}
private static boolean ignoreConstraintTree(Set<? super ConstraintFormula> ignoredConstraints, PsiExpression arg, PsiType parameterType) {
for (Object expr : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
if (PsiTreeUtil.getParentOfType((PsiElement)expr, PsiLambdaExpression.class) == arg) {
@@ -0,0 +1,20 @@
import java.util.function.Function;
class TestClass {
<H> void foo(Function<A, H> f, Function<H, String> toStr) {}
{
foo(o1 -> A.getB(o1), o2 -> o2.getId());
}
}
class A {
static B getB(A a) {
return null;
}
}
interface B {
String getId();
}
@@ -82,7 +82,15 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
doTestAllMethodCallExpressions();
}
public void testLambdaParameterDeterminesNeighbourLambdaType() {
doTestParametersSideEffects();
}
public void testLambdaParameterTypeSideEffects() {
doTestParametersSideEffects();
}
private void doTestParametersSideEffects() {
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
Collection<PsiParameter> parameters = PsiTreeUtil.findChildrenOfType(getFile(), PsiParameter.class);
for (PsiParameter parameter : parameters) {