diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 51c47095e176..a306801d4137 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -977,6 +977,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (myRefCountHolder != null) { myRefCountHolder.registerReference(expression, result); } + if (!myHolder.hasErrorResults()) { + final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); + if (LambdaUtil.dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression, null)) { + myHolder.add(HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, "Cyclic inference")); //todo[ann] append not inferred type params info + } + } } @Override diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 8c3db5070df0..fb437190a0dc 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -355,7 +355,7 @@ public class LambdaUtil { public static boolean dependsOnTypeParams(PsiType type, PsiType functionalInterfaceType, - PsiLambdaExpression lambdaExpression, + PsiElement lambdaExpression, PsiTypeParameter param2Check) { return depends(type, param2Check, new TypeParamsChecker(lambdaExpression, PsiUtil.resolveClassInType(functionalInterfaceType))); @@ -750,11 +750,11 @@ public class LambdaUtil { myClass = aClass; } - public TypeParamsChecker(PsiLambdaExpression expression) { + public TypeParamsChecker(PsiElement expression) { this(expression, PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)).getElement()); } - public TypeParamsChecker(PsiLambdaExpression expression, PsiClass aClass) { + public TypeParamsChecker(PsiElement expression, PsiClass aClass) { myClass = aClass; PsiElement parent = expression.getParent(); while (parent instanceof PsiParenthesizedExpression) { @@ -763,7 +763,11 @@ public class LambdaUtil { if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); if (gParent instanceof PsiCallExpression) { - myMethod = ((PsiCallExpression)gParent).resolveMethod(); + final Map map = MethodCandidateInfo.CURRENT_CANDIDATE.get(); + myMethod = map != null ? map.get(parent) : null; + if (myMethod == null) { + myMethod = ((PsiCallExpression)gParent).resolveMethod(); + } if (myMethod != null && PsiTreeUtil.isAncestor(myMethod, expression, false)) { myMethod = null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 58b162d7d326..8dd78b3b6739 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -594,7 +594,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } @Nullable - private static Pair inferConstraintFromFunctionalInterfaceMethod(PsiTypeParameter typeParam, + private static Pair inferConstraintFromFunctionalInterfaceMethod(final PsiTypeParameter typeParam, final PsiMethodReferenceExpression methodReferenceExpression, final PsiType functionalInterfaceType) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); @@ -607,6 +607,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { methodParamTypes[i] = subst.substitute(methodParameters[i].getType()); } + if (methodParamsDependOn(typeParam, methodReferenceExpression, functionalInterfaceType, methodParameters, subst)) { + return null; + } + final PsiType[] args = new PsiType[methodParameters.length]; final PsiElement resolved = methodReferenceExpression.resolve(); if (resolved instanceof PsiMethod) { @@ -698,12 +702,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return null; } - private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiLambdaExpression lambdaExpression, + private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiElement psiElement, PsiType functionalInterfaceType, PsiParameter[] methodParameters, PsiSubstitutor subst) { for (PsiParameter parameter : methodParameters) { - if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, lambdaExpression, typeParam)) { + if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, psiElement, typeParam)) { return true; } } @@ -948,15 +952,15 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { final PsiExpressionList argumentList = methodCall.getArgumentList(); if (argumentList != null && PsiUtil.getLanguageLevel(argumentList).isAtLeast(LanguageLevel.JDK_1_8)) { for (PsiExpression expression : argumentList.getExpressions()) { - if (expression instanceof PsiLambdaExpression) { - final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType((PsiLambdaExpression)expression, false); + if (expression instanceof PsiLambdaExpression || expression instanceof PsiMethodReferenceExpression) { + final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false); if (functionalInterfaceType == null || PsiUtil.resolveClassInType(functionalInterfaceType) == typeParameter){ return getFailedInferenceConstraint(typeParameter); } final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - if (method == null || methodParamsDependOn(typeParameter, (PsiLambdaExpression)expression, + if (method == null || methodParamsDependOn(typeParameter, expression, functionalInterfaceType, method.getParameterList().getParameters(), LambdaUtil.getSubstitutor(method, resolveResult))) { return getFailedInferenceConstraint(typeParameter); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/CyclicInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/CyclicInference.java new file mode 100644 index 000000000000..56d02be1a403 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/CyclicInference.java @@ -0,0 +1,33 @@ +class MyTest { + MyTest(E e) { + } + + interface I { + MyTest _(T t); + } + + static void bar(Y arg, I i) { + i._(arg); + } + + static void bar(I i, Y arg) { + i._(arg); + } + + static void bar(I i) { + i._(null); + } + + public static void main(String[] args) { + I i = MyTest::new; + + bar("", MyTest::new); + bar("", MyTest::new); + + bar(MyTest::new, ""); + bar(MyTest::new, ""); + + bar(MyTest::new); + bar(MyTest::new); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java index 5339ac10b9a3..4b789afab852 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java @@ -93,6 +93,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testCyclicInference() throws Exception { + doTest(); + } + public void testReturnTypeSpecific() throws Exception { doTest(true); }