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 1c91e6e8066e..672f290abbdc 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -636,22 +636,39 @@ public class LambdaUtil { return result; } - public static void checkMoreSpecificReturnType(List conflicts, int functionalInterfaceIdx) { + public static void checkMoreSpecificReturnType(List conflicts, PsiType[] actualParameterTypes) { final CandidateInfo[] newConflictsArray = conflicts.toArray(new CandidateInfo[conflicts.size()]); for (int i = 1; i < newConflictsArray.length; i++) { final CandidateInfo method = newConflictsArray[i]; - final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method); for (int j = 0; j < i; j++) { final CandidateInfo conflict = newConflictsArray[j]; assert conflict != method; - final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict); - if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) { - int moreSpecific = isMoreSpecific(interfaceReturnType, interfaceReturnType1); - if (moreSpecific > 0) { + int moreSpecific = 0; + final PsiMethod methodElement = (PsiMethod)method.getElement(); + final PsiMethod conflictElement = (PsiMethod)conflict.getElement(); + if (methodElement.isVarArgs() == conflictElement.isVarArgs()) { + for (int functionalInterfaceIdx = 0; functionalInterfaceIdx < actualParameterTypes.length; functionalInterfaceIdx++) { + final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method); + final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict); + if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType || actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) { + if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) { + int moreSpecific1 = isMoreSpecific(interfaceReturnType, interfaceReturnType1); + if (moreSpecific < 0 && moreSpecific1 > 0 || moreSpecific > 0 && moreSpecific1 < 0) { + moreSpecific = 0; + break; + } + moreSpecific = moreSpecific1; + } + } else if (interfaceReturnType != null && interfaceReturnType1 != null) { + moreSpecific = 0; + break; + } + } + if (moreSpecific > 0 && conflictElement.getParameterList().getParametersCount() <= actualParameterTypes.length) { conflicts.remove(method); break; } - else if (moreSpecific < 0) { + else if (moreSpecific < 0 && methodElement.getParameterList().getParametersCount() <= actualParameterTypes.length) { conflicts.remove(conflict); } } @@ -665,7 +682,7 @@ public class LambdaUtil { if (!(returnType1 instanceof PsiPrimitiveType)) { return -1; } else { - return TypeConversionUtil.areTypesConvertible(returnType, returnType1) ? 1 : -1; + return TypeConversionUtil.isAssignable(returnType, returnType1) ? 1 : -1; } } if (returnType1 instanceof PsiPrimitiveType) { diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index a44600573970..09ef657b4c4a 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -686,6 +686,9 @@ public class TypeConversionUtil { final PsiType lType = lLambdaExpression.getFunctionalInterfaceType(); return Comparing.equal(rType, lType); } + if (left instanceof PsiArrayType) { + return false; + } return LambdaUtil.isAcceptable(rLambdaExpression, left, false); } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 7501526a3d69..b8141babaa3f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -126,12 +126,9 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } } } - LambdaUtil.checkMoreSpecificReturnType(conflicts, i); - } - else if (parameterType instanceof PsiMethodReferenceType) { - LambdaUtil.checkMoreSpecificReturnType(conflicts, i); } } + LambdaUtil.checkMoreSpecificReturnType(conflicts, myActualParameterTypes); } public void checkSpecifics(List conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java new file mode 100644 index 000000000000..fab979466120 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java @@ -0,0 +1,82 @@ +public class Test { + + interface II { + int _(); + } + + interface IL { + long _(); + } + + void m0(II im) { } + void m0(IL lm) { } + + { + m0(() -> 1); + m0(null); + } + + void m(II im, IL s) { } + void m(IL lm, II s) { } + + { + m(() -> 1, () ->1); + } + + + void m1(II im, Object s) { } + void m1(IL lm, Object s) { } + + { + m1(() -> 1, null); + m1(() -> 1, ""); + } + + void m2(II im1, II... im) { } + void m2(IL... lm) { } + + + void mi(int im1, int... im) { } + void mi(long... lm) { } + + { + mi (1); + m2(); + m2(()->1); + m2(()->1, ()->1); + m2(()->1, ()->1, ()->1); + + m2(null, null, null); + m2(()->1, null, null); + m2(null, ()->1, null); + m2(null, null, ()->1); + m2(()->1, ()->1, null); + m2(null, ()->1, ()->1); + m2(()->1, null, ()->1); + + m2(()->1L, null, null); + m2(null, ()->1L, null); + m2(null, null, ()->1L); + m2(()->1L, ()->1L, null); + m2(null, ()->1L, ()->1L); + m2(()->1L, null, ()->1L); + m2(()->1L, ()->1L, ()->1L); + } + + void m3(II... im) {} + void m3(IL... lm) {} + + { + m3(); + m3(() -> 1); + m3(() -> 1, () -> 1); + m3(() -> 1, () -> 1, () -> 1); + + m3(null, null); + m3(() -> 1, null); + m3(null, () -> 1); + m3(() -> 1L, null); + m3(null, () -> 1L); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java index 03973993d10a..695bcdb92adf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java @@ -208,6 +208,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testAmbiguityReturnValueResolution1() throws Exception { + doTest(); + } + public void testLambdaOnVarargsPlace1() throws Exception { doTest(); }