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 6649c30c18ff..ea0ee317ab4c 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 @@ -196,7 +196,7 @@ public class InferenceSession { return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); } - if (parent != null) { + if (parentMethod != null) { initReturnTypeConstraint(parentMethod, parent); if (!repeatInferencePhases(true)) { return prepareSubstitution(); @@ -251,7 +251,12 @@ public class InferenceSession { @Nullable PsiExpression[] args, @Nullable PsiElement parent) { final Pair pair = getPair(parent); - final PsiSubstitutor subst = tryToInfer(parameters, args, pair != null ? pair.second : null, pair != null ? pair.first : null); + return infer(parameters, args, parent, pair != null ? pair.first : null); + } + + @NotNull + public PsiSubstitutor infer(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod parentMethod) { + final PsiSubstitutor subst = tryToInfer(parameters, args, parent instanceof PsiCallExpression ? ((PsiCallExpression)parent) : null, parentMethod); if (subst != null) { return subst; } @@ -268,7 +273,7 @@ public class InferenceSession { } else { return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); } - + return prepareSubstitution(); } @@ -340,11 +345,10 @@ public class InferenceSession { returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context); PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); if (targetType == null) { - final PsiType finalReturnType = returnType; targetType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, false, new Computable() { @Override public PsiType compute() { - return getTargetType(context, finalReturnType); + return getTargetType(context); } }); } @@ -466,7 +470,7 @@ public class InferenceSession { return false; } - private PsiType getTargetType(final PsiExpression context, PsiType returnType) { + private PsiType getTargetType(final PsiExpression context) { final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); @@ -474,49 +478,50 @@ public class InferenceSession { final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList(); if (argumentList != null) { final Pair pair = MethodCandidateInfo.getCurrentMethod(argumentList); - if (pair == null) { - final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) { - @Override - protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { - if (argumentList != null) { - final PsiExpression[] expressions = argumentList.getExpressions(); - final int idx = LambdaUtil.getLambdaIdx(argumentList, context); - final PsiType[] types = PsiType.createArray(expressions.length); - for (int i = 0; i < expressions.length; i++) { - if (i != idx) { - types[i] = expressions[i].getType(); - } - else { - types[i] = PsiType.NULL; - } + final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) { + @Override + protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { + if (argumentList != null) { + final PsiExpression[] expressions = argumentList.getExpressions(); + final int idx = LambdaUtil.getLambdaIdx(argumentList, context); + final PsiType[] types = PsiType.createArray(expressions.length); + for (int i = 0; i < expressions.length; i++) { + if (i != idx) { + types[i] = expressions[i].getType(); + } + else { + types[i] = PsiType.NULL; } - return types; - } - else { - return null; } + return types; + } + else { + return null; } - }; - try { - PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false); } - catch (MethodProcessorSetupFailedException e) { - return null; - } - final JavaResolveResult[] results = processor.getResult(); - return results.length == 1 ? getTypeByMethod(context, argumentList, null, results[0], results[0].getElement()) : null; + }; + try { + PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false); } - return getTypeByMethod(context, argumentList, pair, null, pair.first); + catch (MethodProcessorSetupFailedException e) { + return null; + } + final JavaResolveResult[] results = processor.getResult(); + return results.length == 1 ? getTypeByMethod(context, argumentList, pair, results[0], results[0].getElement()) : null; } } } else if (parent instanceof PsiConditionalExpression) { PsiType targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent); if (targetType == null) { - targetType = getTargetType((PsiExpression)parent, returnType); + targetType = getTargetType((PsiExpression)parent); } return targetType; } else if (parent instanceof PsiLambdaExpression) { + if (PsiUtil.skipParenthesizedExprUp(parent.getParent()) instanceof PsiExpressionList) { + final PsiType typeTypeByParentCall = getTargetType((PsiLambdaExpression)parent); + return LambdaUtil.getFunctionalInterfaceReturnType(FunctionalInterfaceParameterizationUtil.getGroundTargetType(typeTypeByParentCall, (PsiLambdaExpression)parent)); + } return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType()); } return null; @@ -537,28 +542,23 @@ public class InferenceSession { } final int i = ArrayUtilRt.find(args, arg); if (i < 0) return null; - if (pair != null) { - return getParameterType(parameters, args, i, pair.second); + final PsiCallExpression callExpression = (PsiCallExpression)argumentList.getParent(); + if (callExpression.getTypeArguments().length > 0) { + return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor()); } - else { - final PsiCallExpression callExpression = (PsiCallExpression)argumentList.getParent(); - if (callExpression.getTypeArguments().length > 0) { - return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor()); - } - final PsiType parameterType = getParameterType(parameters, args, i, PsiSubstitutor.EMPTY); - args[i] = null; - final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters(); - final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList); - session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod); - if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) { - return null; - } - final Collection params = session.getTypeParams(); - initBounds(params.toArray(new PsiTypeParameter[params.size()])); - liftBounds(session.getInferenceVariables()); - final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor(); - return substitutor.substitute(parameterType); + final PsiType parameterType = getParameterType(parameters, args, i, pair != null ? pair.second : PsiSubstitutor.EMPTY); + args[i] = null; + final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters(); + final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList); + session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod); + if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) { + return null; } + final Collection params = session.getTypeParams(); + initBounds(params.toArray(new PsiTypeParameter[params.size()])); + liftBounds(session.getInferenceVariables()); + final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor(); + return substitutor.substitute(parameterType); } return null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index e2e0275efe2d..d6a1d834c60f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -49,7 +49,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm } final PsiType exprType = myExpression.getType(); - if (exprType != null) { + if (exprType != null && exprType != PsiType.NULL) { constraints.add(new TypeCompatibilityConstraint(myT, exprType)); } return true; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/FunctionalInterfacesCalculation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/FunctionalInterfacesCalculation.java new file mode 100644 index 000000000000..5e2981fb8186 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/FunctionalInterfacesCalculation.java @@ -0,0 +1,26 @@ + +import java.util.Optional; +import java.util.function.Function; + +import static java.util.Optional.of; + +class MatchTest { + + { + Match match = match((String s) -> s.equals("1") ? of(1) : null, s -> 1); + } + + private Optional bar() { + return null; + } + + public static Match match(Extractor e, Function c) { + return null; + } + + class Match {} + + interface Extractor { + Optional unapply(T t); + } +} 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 bfac8d363f52..820ebae10909 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 @@ -110,6 +110,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testAdditionalConstraintSubstitution() throws Exception { doTest(); } + public void testFunctionalInterfacesCalculation() throws Exception { + doTest(); + } + private void doTest() { doTest(false);