diff options
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.java | 213 |
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) { |