From e5afaa7a583e5788e82cb6fb9971036ce857a900 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 1 Sep 2014 21:29:37 +0400 Subject: [PATCH] new inference: process additional constraints one after another and use data from previous results (IDEA-124983) --- .../graphInference/InferenceSession.java | 99 ++++++++++++------- ...mbdaExpressionCompatibilityConstraint.java | 6 +- ...NestedLambdaExpressionsNoFormalParams.java | 52 ++++++++++ .../lambda/NewLambdaHighlightingTest.java | 2 +- 4 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index b4b718535532..8ac514e3e1d7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -267,11 +267,9 @@ public class InferenceSession { boolean varargs, boolean toplevel) { for (int i = 0; i < args.length; i++) { if (args[i] != null) { - InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(args[i], PsiCallExpression.class)); - if (session == null) { - session = this; - } - PsiType parameterType = session.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); + final InferenceSession nestedCallSession = findNestedCallSession(args[i]); + final PsiType parameterType = + nestedCallSession.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); if (!isPertinentToApplicability(args[i], parentMethod)) { additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType)); } @@ -881,45 +879,66 @@ public class InferenceSession { //extract subset of constraints final Set subset = buildSubset(additionalConstraints); - //collect all input variables of selection + //collect all input variables of selection final Set varsToResolve = new LinkedHashSet(); for (ConstraintFormula formula : subset) { if (formula instanceof InputOutputConstraintFormula) { - final Set inputVariables = ((InputOutputConstraintFormula)formula).getInputVariables(this); - if (inputVariables != null) { - for (InferenceVariable inputVariable : inputVariables) { - varsToResolve.addAll(inputVariable.getDependencies(this)); - } - varsToResolve.addAll(inputVariables); - } + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); } } - //resolve input variables - PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); - if (substitutor == null) { + for (ConstraintFormula formula : subset) { + if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false; + } + } + return true; + } + + private void collectVarsToResolve(Set varsToResolve, InputOutputConstraintFormula formula) { + final Set inputVariables = formula.getInputVariables(this); + if (inputVariables != null) { + for (InferenceVariable inputVariable : inputVariables) { + varsToResolve.addAll(inputVariable.getDependencies(this)); + } + varsToResolve.addAll(inputVariables); + } + } + + private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set varsToResolve) { + if (formula instanceof ExpressionCompatibilityConstraint) { + final PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression(); + final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(expression, PsiCallExpression.class, false); + if (callExpression != null) { + final InferenceSession session = myNestedSessions.get(callExpression); + if (session != null) { + formula.apply(session.myInferenceSubstitution, true); + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); + } + } + } + + //resolve input variables + PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); + if (substitutor == null) { + return false; + } + + if (myContext instanceof PsiCallExpression) { + PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); + LOG.assertTrue(argumentList != null); + MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); + } + + try { + formula.apply(substitutor, true); + + myConstraints.add(formula); + if (!repeatInferencePhases(true)) { return false; } - - if (myContext instanceof PsiCallExpression) { - PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); - LOG.assertTrue(argumentList != null); - MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); - } - - try { - for (ConstraintFormula additionalConstraint : subset) { - additionalConstraint.apply(substitutor, true); - } - - myConstraints.addAll(subset); - if (!repeatInferencePhases(true)) { - return false; - } - } - finally { - LambdaUtil.ourFunctionTypes.set(null); - } + } + finally { + LambdaUtil.ourFunctionTypes.set(null); } return true; } @@ -1316,6 +1335,14 @@ public class InferenceSession { return myInferenceSubstitution.substitute(type); } + public InferenceSession findNestedCallSession(PsiExpression arg) { + InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(arg, PsiCallExpression.class)); + if (session == null) { + session = this; + } + return session; + } + public PsiType startWithFreshVars(PsiType type) { PsiSubstitutor s = PsiSubstitutor.EMPTY; for (InferenceVariable variable : myInferenceVariables) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java index c282481e79c0..f7e9badfa33c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java @@ -3,6 +3,7 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; 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.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import java.util.List; @@ -62,8 +63,9 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul if (returnExpressions.isEmpty() && !myExpression.isValueCompatible()) { //not value-compatible return false; } - returnType = session.substituteWithInferenceVariables(substitutor.substitute(returnType)); - if (!session.isProperType(returnType)) { + InferenceSession callsession = session.findNestedCallSession(myExpression); + returnType = callsession.substituteWithInferenceVariables(substitutor.substitute(returnType)); + if (!callsession.isProperType(returnType)) { for (PsiExpression returnExpression : returnExpressions) { constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType)); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java new file mode 100644 index 000000000000..7d9d1bc9a837 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java @@ -0,0 +1,52 @@ +import java.util.function.Function; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import javafx.scene.Group; +import javafx.scene.shape.Rectangle; + +abstract class NoFormalParams { + interface I { + T a(int a); + } + + I foo(I i) { return null;} + + { + I i = foo(a -> foo(b -> 1)).a(0); + foo(a -> foo(b -> 1)).a(0); + } +} + +abstract class NoFormalParamTypeInferenceNeeded { + interface I { + T a(int a); + } + + abstract RR map(I mapper); + abstract R zip(Function zipper); + + { + map(a -> zip(text -> text)); + zip(a -> zip(text -> text)); + Integer zip = zip(a -> zip(text -> text)); + } + +} + +class IDEA124983 { + private final Group gridGroup = new Group(); + void createGrid() { + IntStream.range(0, 4) + .mapToObj(i -> IntStream.range(0, 4).mapToObj(j -> { + Rectangle rect2 = new Rectangle(i * 64, j * 64, 64, 64); + return rect2; + })) + .flatMap(s -> s) + .forEach(gridGroup.getChildren()::add); + } + + void simplified(final IntStream range) { + range.mapToObj(i -> range.mapToObj(j -> 1)).flatMap(s -> s); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index e31cb8989ed2..1821b9334788 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -76,7 +76,6 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEA122616() { doTest(); } public void testIDEA122700() { doTest(); } public void testIDEA122406() { doTest(); } - @Bombed(day = 30, month = Calendar.SEPTEMBER) public void testNestedCallsInsideLambdaReturnExpression() { doTest(); } @Bombed(day = 30, month = Calendar.SEPTEMBER) public void testIDEA123731() { doTest(); } @@ -95,6 +94,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEA126809() { doTest(); } public void testIDEA124424() { doTest(); } public void testNestedLambdaExpressions1() { doTest(); } + public void testNestedLambdaExpressionsNoFormalParams() { doTest(); } public void testIDEA127596() throws Exception { doTest();