summaryrefslogtreecommitdiff
path: root/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java')
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java213
1 files changed, 140 insertions, 73 deletions
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 35db6c29bc0c..a1b4570e5361 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
@@ -174,7 +174,6 @@ public class InferenceSession {
}
}
}
- return true;
}
if (expr instanceof PsiLambdaExpression) {
if (!((PsiLambdaExpression)expr).hasFormalParameterTypes()) {
@@ -234,7 +233,7 @@ public class InferenceSession {
!MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(parent.getParent()))) {
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
if (parameters.length > 0) {
- collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs(), true);
+ collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
@@ -264,67 +263,113 @@ public class InferenceSession {
PsiMethod parentMethod,
PsiSubstitutor siteSubstitutor,
Set<ConstraintFormula> additionalConstraints,
- boolean varargs, boolean toplevel) {
+ boolean varargs) {
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));
- if (!isPertinentToApplicability(args[i], parentMethod)) {
- additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
+ final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]);
+ if (arg != null) {
+ final InferenceSession nestedCallSession = findNestedCallSession(arg);
+ final PsiType parameterType =
+ nestedCallSession.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs));
+ if (!isPertinentToApplicability(arg, parentMethod)) {
+ additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
}
- additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
- if (args[i] instanceof PsiCallExpression && PsiPolyExpressionUtil.isPolyExpression(args[i])) {
+ additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType));
+ if (arg instanceof PsiCallExpression) {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
- final PsiCallExpression callExpression = (PsiCallExpression)args[i];
- collectAdditionalConstraints(additionalConstraints, callExpression);
- } else if (args[i] instanceof PsiLambdaExpression && toplevel) {
- final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
- if (interfaceReturnType != null) {
- final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)args[i]);
- for (PsiExpression returnExpression : returnExpressions) {
- if (returnExpression instanceof PsiCallExpression) {
- final PsiCallExpression callExpression = (PsiCallExpression)returnExpression;
- collectAdditionalConstraints(additionalConstraints, callExpression);
- }
- }
+ final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)arg);
+ if (PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) {
+ collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)arg);
}
+ } else if (arg instanceof PsiLambdaExpression) {
+ collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType);
}
}
}
}
+ private static PsiMethod getCalledMethod(PsiCallExpression arg) {
+ final PsiExpressionList argumentList = arg.getArgumentList();
+ if (argumentList == null || argumentList.getExpressions().length == 0) {
+ return null;
+ }
+
+ MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
+ if (properties != null) {
+ return properties.getMethod();
+ }
+ final JavaResolveResult resolveResult = getMethodResult(arg);
+ return resolveResult instanceof MethodCandidateInfo ? (PsiMethod)resolveResult.getElement() : null;
+ }
+
+ private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints,
+ PsiLambdaExpression lambdaExpression,
+ PsiType parameterType) {
+ final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
+ if (interfaceReturnType != null) {
+ final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
+ for (PsiExpression returnExpression : returnExpressions) {
+ processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType);
+ }
+ }
+ }
+
+ private void processReturnExpression(Set<ConstraintFormula> additionalConstraints,
+ PsiExpression returnExpression,
+ PsiType functionalType) {
+ if (returnExpression instanceof PsiCallExpression) {
+ final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
+ if (PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
+ collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression);
+ }
+ }
+ else if (returnExpression instanceof PsiParenthesizedExpression) {
+ processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType);
+ }
+ else if (returnExpression instanceof PsiConditionalExpression) {
+ processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType);
+ processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType);
+ }
+ else if (returnExpression instanceof PsiLambdaExpression) {
+ collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType);
+ }
+ }
+
private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints,
final PsiCallExpression callExpression) {
PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
- final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class);
- final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() {
- @Override
- public JavaResolveResult compute() {
- return callExpression.resolveMethodGenerics();
- }
- };
+ final JavaResolveResult result = getMethodResult(callExpression);
MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
- final JavaResolveResult result = properties != null ? null :
- expression == null
- ? computableResolve.compute()
- : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null;
if (method != null) {
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, result != null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : properties.getSubstitutor(),
- additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs(), false);
+ additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs());
}
}
}
}
+ private static JavaResolveResult getMethodResult(final PsiCallExpression callExpression) {
+ final PsiExpressionList argumentList = callExpression.getArgumentList();
+
+ final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class);
+ final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() {
+ @Override
+ public JavaResolveResult compute() {
+ return callExpression.resolveMethodGenerics();
+ }
+ };
+ MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
+ return properties != null ? null :
+ expression == null
+ ? computableResolve.compute()
+ : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
+ }
+
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
for (InferenceVariable variable : variables) {
@@ -702,7 +747,7 @@ public class InferenceSession {
}
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
- final PsiTypeParameter[] freshParameters = createFreshVariables(vars);
+ final PsiTypeParameter[] freshParameters = createFreshVariables(vars, substitutor);
for (int i = 0; i < freshParameters.length; i++) {
PsiTypeParameter parameter = freshParameters[i];
final InferenceVariable var = vars.get(i);
@@ -725,7 +770,7 @@ public class InferenceSession {
return substitutor;
}
- private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars) {
+ private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars, final PsiSubstitutor siteSubstitutor) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
@@ -742,7 +787,7 @@ public class InferenceSession {
final String classText = "class I<" + StringUtil.join(vars, new Function<InferenceVariable, String>() {
@Override
public String fun(InferenceVariable variable) {
- final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true);
+ final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(siteSubstitutor), true);
return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText();
}
}, ", ") + ">{}";
@@ -860,46 +905,67 @@ public class InferenceSession {
//extract subset of constraints
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints);
- //collect all input variables of selection
+ //collect all input variables of selection
final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>();
for (ConstraintFormula formula : subset) {
if (formula instanceof InputOutputConstraintFormula) {
- final Set<InferenceVariable> 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) {
- return false;
+ for (ConstraintFormula formula : subset) {
+ if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false;
}
+ }
+ return true;
+ }
- if (myContext instanceof PsiCallExpression) {
- PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList();
- LOG.assertTrue(argumentList != null);
- MethodCandidateInfo.updateSubstitutor(argumentList, substitutor);
+ private void collectVarsToResolve(Set<InferenceVariable> varsToResolve, InputOutputConstraintFormula formula) {
+ final Set<InferenceVariable> inputVariables = formula.getInputVariables(this);
+ if (inputVariables != null) {
+ for (InferenceVariable inputVariable : inputVariables) {
+ varsToResolve.addAll(inputVariable.getDependencies(this));
}
+ varsToResolve.addAll(inputVariables);
+ }
+ }
- try {
- for (ConstraintFormula additionalConstraint : subset) {
- additionalConstraint.apply(substitutor, true);
- }
-
- myConstraints.addAll(subset);
- if (!repeatInferencePhases(true)) {
- return false;
+ private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set<InferenceVariable> 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);
}
}
- finally {
- LambdaUtil.ourFunctionTypes.set(null);
+ }
+
+ //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;
}
}
+ finally {
+ LambdaUtil.ourFunctionTypes.set(null);
+ }
return true;
}
@@ -1139,9 +1205,6 @@ public class InferenceSession {
}
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg);
- if (sReturnType == PsiType.VOID) {
- return returnExpressions.isEmpty() && session == null;
- }
if (LambdaUtil.isFunctionalType(sReturnType) && LambdaUtil.isFunctionalType(tReturnType) &&
!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(sReturnType), TypeConversionUtil.erasure(tReturnType)) &&
@@ -1197,10 +1260,6 @@ public class InferenceSession {
return true;
}
- if (sReturnType == PsiType.VOID && session != null) {
- return false;
- }
-
final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && sReturnType != PsiType.VOID;
final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && tReturnType != PsiType.VOID;
@@ -1295,6 +1354,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) {