mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
new inference: collect additional constraints from lambda return expressions when lambda parameters are already fixed; process constraints without input variables before others, so their 'return' expressions could influence next rounds; testdata (IDEA-144596)
This commit is contained in:
@@ -345,7 +345,10 @@ public class InferenceSession {
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)arg);
|
||||
}
|
||||
} else if (arg instanceof PsiLambdaExpression && !isProperType(retrieveNonPrimitiveEqualsBounds(myInferenceVariables).substitute(parameterType))) {
|
||||
}
|
||||
else if (arg instanceof PsiLambdaExpression &&
|
||||
isPertinentToApplicability(arg, parentMethod) &&
|
||||
!isProperType(retrieveNonPrimitiveEqualsBounds(myInferenceVariables).substitute(parameterType))) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType);
|
||||
}
|
||||
}
|
||||
@@ -354,21 +357,7 @@ public class InferenceSession {
|
||||
|
||||
private static PsiMethod getCalledMethod(PsiCallExpression arg) {
|
||||
final PsiExpressionList argumentList = arg.getArgumentList();
|
||||
if (argumentList == null || argumentList.getExpressions().length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
for (PsiExpression expression : argumentList.getExpressions()) {
|
||||
expression = PsiUtil.skipParenthesizedExprDown(expression);
|
||||
if (expression instanceof PsiConditionalExpression ||
|
||||
expression instanceof PsiCallExpression ||
|
||||
expression instanceof PsiFunctionalExpression) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (argumentList == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1121,7 +1110,7 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
for (ConstraintFormula formula : subset) {
|
||||
if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false;
|
||||
if (!processOneConstraint(formula, siteSubstitutor, varsToResolve, additionalConstraints)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1137,7 +1126,10 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set<InferenceVariable> varsToResolve) {
|
||||
private boolean processOneConstraint(ConstraintFormula formula,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
Set<InferenceVariable> varsToResolve,
|
||||
Set<ConstraintFormula> additionalConstraints) {
|
||||
if (formula instanceof ExpressionCompatibilityConstraint) {
|
||||
final PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
|
||||
final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(expression, PsiCallExpression.class, false);
|
||||
@@ -1169,6 +1161,16 @@ public class InferenceSession {
|
||||
if (!repeatInferencePhases(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (formula instanceof ExpressionCompatibilityConstraint) {
|
||||
PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
PsiType parameterType = ((ExpressionCompatibilityConstraint)formula).getT();
|
||||
if (!isProperType(parameterType)) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)expression, parameterType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
LambdaUtil.ourFunctionTypes.set(null);
|
||||
@@ -1178,7 +1180,7 @@ public class InferenceSession {
|
||||
|
||||
private Set<ConstraintFormula> buildSubset(final Set<ConstraintFormula> additionalConstraints) {
|
||||
|
||||
final Set<ConstraintFormula> subset = new LinkedHashSet<ConstraintFormula>();
|
||||
Set<ConstraintFormula> subset = new LinkedHashSet<ConstraintFormula>();
|
||||
final Set<InferenceVariable> outputVariables = new HashSet<InferenceVariable>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
@@ -1190,6 +1192,7 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
Set<ConstraintFormula> noInputVariables = new LinkedHashSet<ConstraintFormula>();
|
||||
for (ConstraintFormula constraint : additionalConstraints) {
|
||||
if (constraint instanceof InputOutputConstraintFormula) {
|
||||
final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)constraint).getInputVariables(this);
|
||||
@@ -1217,10 +1220,15 @@ public class InferenceSession {
|
||||
}
|
||||
if (!dependsOnOutput) {
|
||||
subset.add(constraint);
|
||||
|
||||
if (inputVariables.isEmpty()) {
|
||||
noInputVariables.add(constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
subset.add(constraint);
|
||||
noInputVariables.add(constraint);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1230,6 +1238,10 @@ public class InferenceSession {
|
||||
if (subset.isEmpty()) {
|
||||
subset.add(additionalConstraints.iterator().next()); //todo choose one constraint
|
||||
}
|
||||
|
||||
if (!noInputVariables.isEmpty()) {
|
||||
subset = noInputVariables;
|
||||
}
|
||||
|
||||
additionalConstraints.removeAll(subset);
|
||||
return subset;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Test {
|
||||
public void testIt()
|
||||
{
|
||||
Map<Integer, String> innerMap = new HashMap<>();
|
||||
innerMap.put(2, "abc");
|
||||
Map<Long, Map<Integer, String>> outerMap = new HashMap<>();
|
||||
outerMap.put(1L, innerMap);
|
||||
Map<Long, Map<Integer, String>> transformedMap = outerMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
m -> m.getValue().entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
v -> v.getValue().toUpperCase()))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
class FooBar {
|
||||
|
||||
void p(Map<String, String> m) {
|
||||
m.entrySet().stream()
|
||||
.collect(Collector.of(() -> new HashMap<>(),
|
||||
(a, e) -> a.put(e.getValue(), e.getKey()),
|
||||
(l, r) -> {
|
||||
l.put<caret>All(r);
|
||||
return l;
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testCacheUnresolvedMethods2() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
public void testCacheUnresolvedMethods3() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
private void doTestCachedUnresolved() {
|
||||
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
|
||||
@@ -80,6 +84,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdditionalConstraintsBasedOnLambdaResolution() throws Exception {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
private void doTestAllMethodCallExpressions() {
|
||||
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
|
||||
final Collection<PsiCallExpression> methodCallExpressions = PsiTreeUtil.findChildrenOfType(getFile(), PsiCallExpression.class);
|
||||
|
||||
Reference in New Issue
Block a user