From 82fd892ec5548f180b82fbe4c1d5a96890b01d41 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 19 Nov 2013 17:52:23 +0100 Subject: [PATCH] new inference: overload resolution: check SAM specific withing common specific check (cherry picked from commit 2bbd45e57bc5df7ff2a5cae7acedc0d2428d9afe) --- .../JavaMethodsConflictResolver.java | 178 +++++++++--------- .../newLambda/OverloadResolutionSAM.java | 20 ++ .../lambda/NewLambdaHighlightingTest.java | 4 + 3 files changed, 111 insertions(+), 91 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/OverloadResolutionSAM.java 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 224185117c4f..94b4d4512fa7 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 @@ -124,24 +124,11 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiType paramType = param.getType(); if (!LambdaUtil.isAcceptable(lambdaExpression, conflict.getSubstitutor().substitute(paramType), lambdaExpression.hasFormalParameterTypes())) { iterator.remove(); - } else { - /*todo - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(paramType); - final PsiMethod functionalInterfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(paramType); - if (functionalInterfaceMethod != null) { - for (PsiParameter parameter : functionalInterfaceMethod.getParameterList().getParameters()) { - if (LambdaUtil.dependsOnTypeParams(resolveResult.getSubstitutor().substitute(parameter.getType()), resolveResult.getElement(), method)) { - iterator.remove(); - break; - } - } - }*/ } } } } } - checkMoreSpecificReturnType(conflicts, getActualParameterTypes(), languageLevel); } public void checkSpecifics(@NotNull List conflicts, @@ -522,11 +509,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiType[] types2AtSite = typesAtSite(types2, siteSubstitutor2); final PsiType[] types1AtSite = typesAtSite(types1, siteSubstitutor1); - final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel); - final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel); - - final boolean applicable12 = isApplicableTo(types2AtSite, method1, typeParameters1, languageLevel, methodSubstitutor1, varargsPosition); - final boolean applicable21 = isApplicableTo(types1AtSite, method2, typeParameters2, languageLevel, methodSubstitutor2, varargsPosition); + final boolean applicable12 = isApplicableTo(types2AtSite, method1, typeParameters1, languageLevel, varargsPosition, types1, siteSubstitutor1); + final boolean applicable21 = isApplicableTo(types1AtSite, method2, typeParameters2, languageLevel, varargsPosition, types2, siteSubstitutor2); if (applicable12 || applicable21) { @@ -542,6 +526,53 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return Specifics.FIRST; } } + if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + boolean toCompareFunctional = false; + for (int i = 0; i < myActualParameterTypes.length; i++) { + if (types1.length > 0 && LambdaHighlightingUtil.checkInterfaceFunctional(types1[Math.min(i, types1.length - 1)]) == null && + types2.length > 0 && LambdaHighlightingUtil.checkInterfaceFunctional(types2[Math.min(i, types2.length - 1)]) == null) { + types1AtSite[Math.min(i, types1.length - 1)] = PsiType.NULL; + types2AtSite[Math.min(i, types2.length - 1)] = PsiType.NULL; + toCompareFunctional = true; + } + } + + if (toCompareFunctional) { + final boolean applicable12ignoreFunctionalType = isApplicableTo(types2AtSite, method1, typeParameters1, languageLevel, varargsPosition, types1, siteSubstitutor1); + final boolean applicable21ignoreFunctionalType = isApplicableTo(types1AtSite, method2, typeParameters2, languageLevel, varargsPosition, types2, siteSubstitutor2); + + if (applicable12ignoreFunctionalType || applicable21ignoreFunctionalType) { + Specifics specifics = null; + for (int i = 0; i < myActualParameterTypes.length; i++) { + if (types1.length > 0 && types1AtSite[Math.min(i, types1.length - 1)] == PsiType.NULL && + types2.length > 0 && types2AtSite[Math.min(i, types2.length - 1)] == PsiType.NULL) { + Specifics specific = compareFunctionalTypes(info1, info2, myActualParameterTypes[i], i, languageLevel); + if (specific == Specifics.NEITHER) { + specifics = Specifics.NEITHER; + break; + } + + if (specifics == null) { + specifics = specific; + } else if (specifics != specific) { + specifics = Specifics.NEITHER; + break; + } + } + } + + if (applicable12ignoreFunctionalType && !applicable21ignoreFunctionalType) { + return specifics == Specifics.SECOND ? Specifics.SECOND : Specifics.NEITHER; + } + + if (applicable21ignoreFunctionalType && !applicable12ignoreFunctionalType) { + return specifics == Specifics.FIRST ? Specifics.FIRST : Specifics.NEITHER; + } + + return specifics; + } + } + } } else if (varargsPosition) { final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]); @@ -585,13 +616,15 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return Specifics.NEITHER; } - private boolean isApplicableTo(PsiType[] argTypes, - PsiMethod method, - PsiTypeParameter[] typeParameters, - LanguageLevel languageLevel, PsiSubstitutor methodSubstitutor, boolean checkVarargs) { - final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, methodSubstitutor, argTypes, languageLevel, false, checkVarargs); + private boolean isApplicableTo(PsiType[] types2AtSite, + PsiMethod method1, + PsiTypeParameter[] typeParameters1, + LanguageLevel languageLevel, + boolean varargsPosition, PsiType[] types1, PsiSubstitutor siteSubstitutor1) { + final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, languageLevel); + final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method1, methodSubstitutor1, types2AtSite, languageLevel, false, varargsPosition); final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE; - if (applicable && !GenericsUtil.isTypeArgumentsApplicable(typeParameters, methodSubstitutor, myArgumentsList, false)) { + if (applicable && !GenericsUtil.isTypeArgumentsApplicable(typeParameters1, methodSubstitutor1, myArgumentsList, false)) { return false; } return applicable; @@ -662,77 +695,40 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ PRIMITIVE, REFERENCE, NONE_DETERMINED } - public void checkMoreSpecificReturnType(List conflicts, PsiType[] actualParameterTypes, LanguageLevel languageLevel) { - final CandidateInfo[] newConflictsArray = conflicts.toArray(new CandidateInfo[conflicts.size()]); - next: - for (int i = 1; i < newConflictsArray.length; i++) { - final CandidateInfo method = newConflictsArray[i]; - for (int j = 0; j < i; j++) { - final CandidateInfo conflict = newConflictsArray[j]; - assert conflict != method; - switch (isMoreSpecific(method, conflict, actualParameterTypes, languageLevel)) { - case FIRST: - conflicts.remove(conflict); - break; - case SECOND: - conflicts.remove(method); - continue next; - default: - break; - } - } - } - } - - private static Specifics isMoreSpecific(CandidateInfo method, - CandidateInfo conflict, - PsiType[] actualParameterTypes, - LanguageLevel languageLevel) { - Specifics moreSpecific = Specifics.NEITHER; + private static Specifics compareFunctionalTypes(CandidateInfo method, + CandidateInfo conflict, + PsiType paramType, + int functionalInterfaceIdx, + LanguageLevel languageLevel) { final PsiMethod methodElement = (PsiMethod)method.getElement(); final PsiMethod conflictElement = (PsiMethod)conflict.getElement(); - if (methodElement != null && - conflictElement != null && - methodElement.isVarArgs() == conflictElement.isVarArgs() && - methodElement.getParameterList().getParametersCount() <= actualParameterTypes.length && - conflictElement.getParameterList().getParametersCount() <= actualParameterTypes.length) { - 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) { - final PsiLambdaExpression lambdaExpression = ((PsiLambdaExpressionType)actualParameterTypes[functionalInterfaceIdx]).getExpression(); - if (!lambdaExpression.hasFormalParameterTypes()) { - return Specifics.NEITHER; - } - } - if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) { - final PsiMethodReferenceExpression - methodReferenceExpression = ((PsiMethodReferenceType)actualParameterTypes[functionalInterfaceIdx]).getExpression(); - if (!methodReferenceExpression.isExact()) { - return Specifics.NEITHER; - } - } - if (actualParameterTypes[functionalInterfaceIdx] instanceof PsiLambdaExpressionType || actualParameterTypes[functionalInterfaceIdx] instanceof PsiMethodReferenceType) { - if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) { - Specifics moreSpecific1 = comparePrimitives(actualParameterTypes[functionalInterfaceIdx], interfaceReturnType, interfaceReturnType1); - if (moreSpecific1 == Specifics.NEITHER && (interfaceReturnType != PsiType.VOID && interfaceReturnType1 != PsiType.VOID)) { - moreSpecific1 = compareConflicts((MethodCandidateInfo)method, (MethodCandidateInfo)conflict, - methodElement, conflictElement, - interfaceReturnType, interfaceReturnType1, languageLevel); - } - - if (moreSpecific != Specifics.NEITHER && moreSpecific != moreSpecific1) { - return Specifics.NEITHER; - } - - moreSpecific = moreSpecific1; - } - } else if (interfaceReturnType != null && interfaceReturnType1 != null) { - return Specifics.NEITHER; - } + final PsiType interfaceReturnType = getReturnType(functionalInterfaceIdx, method); + final PsiType interfaceReturnType1 = getReturnType(functionalInterfaceIdx, conflict); + if (paramType instanceof PsiLambdaExpressionType) { + final PsiLambdaExpression lambdaExpression = ((PsiLambdaExpressionType)paramType).getExpression(); + if (!lambdaExpression.hasFormalParameterTypes()) { + return Specifics.NEITHER; } } - return moreSpecific; + if (paramType instanceof PsiMethodReferenceType) { + final PsiMethodReferenceExpression + methodReferenceExpression = ((PsiMethodReferenceType)paramType).getExpression(); + if (!methodReferenceExpression.isExact()) { + return Specifics.NEITHER; + } + } + if (paramType instanceof PsiLambdaExpressionType || paramType instanceof PsiMethodReferenceType) { + if (interfaceReturnType != null && interfaceReturnType1 != null && !Comparing.equal(interfaceReturnType, interfaceReturnType1)) { + Specifics moreSpecific1 = comparePrimitives(paramType, interfaceReturnType, interfaceReturnType1); + if (moreSpecific1 == Specifics.NEITHER && (interfaceReturnType != PsiType.VOID && interfaceReturnType1 != PsiType.VOID)) { + return compareConflicts((MethodCandidateInfo)method, (MethodCandidateInfo)conflict, + methodElement, conflictElement, + interfaceReturnType, interfaceReturnType1, languageLevel); + } + return moreSpecific1; + } + } + return Specifics.NEITHER; } private static Specifics compareConflicts(MethodCandidateInfo method, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/OverloadResolutionSAM.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/OverloadResolutionSAM.java new file mode 100644 index 000000000000..a76b40505e07 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/OverloadResolutionSAM.java @@ -0,0 +1,20 @@ +class Test { + interface IInt { + int _(); + } + + interface ILong { + long _(); + } + + void m(IInt i, Long l) {} + void m(ILong l, Integer i) {} + + void m1(IInt i, Integer l) {} + void m1(ILong l, Object i) {} + + void test() { + m(() -> 1, null); + m1(() -> 1, null); + } +} \ No newline at end of file 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 58e77321a8aa..084647e82034 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 @@ -66,6 +66,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testOverloadResolutionSAM() throws Exception { + doTest(); + } + private void doTest() { doTest(false); }