From b540bb262e3e60ad41c8a51be674a219eceff6de Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 6 Jun 2019 15:57:14 +0200 Subject: [PATCH] overload resolution: ensure type parameters of containing class are fixed during most specific inference (IDEA-205886) GitOrigin-RevId: 01b3a6f25c68e27475a053c74a7765e84147beca --- .../graphInference/InferenceSession.java | 17 +---------------- .../JavaMethodsConflictResolver.java | 15 +++++++++------ .../FixedContainingClassTypeArguments.java | 13 +++++++++++++ .../daemon/lambda/OverloadResolutionTest.java | 1 + 4 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/FixedContainingClassTypeArguments.java 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 a31605261ffc..f75aef9939ae 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 @@ -1637,14 +1637,7 @@ public class InferenceSession { PsiElement context, boolean varargs) { - List params = new ArrayList<>(); - for (PsiTypeParameter param : PsiUtil.typeParametersIterable(m2)) { - params.add(param); - } - - siteSubstitutor1 = getSiteSubstitutor(siteSubstitutor1, params); - - final InferenceSession session = new InferenceSession(params.toArray(PsiTypeParameter.EMPTY_ARRAY), siteSubstitutor1, m2.getManager(), context); + final InferenceSession session = new InferenceSession(m2.getTypeParameters(), siteSubstitutor1, m2.getManager(), context); final PsiParameter[] parameters1 = m1.getParameterList().getParameters(); final PsiParameter[] parameters2 = m2.getParameterList().getParameters(); @@ -1684,14 +1677,6 @@ public class InferenceSession { return session.repeatInferencePhases(); } - private static PsiSubstitutor getSiteSubstitutor(PsiSubstitutor siteSubstitutor1, List params) { - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - for (PsiTypeParameter param : params) { - subst = subst.put(param, siteSubstitutor1.substitute(param)); - } - return subst; - } - /** * 15.12.2.5 Choosing the Most Specific Method * "a functional interface type S is more specific than a functional interface type T for an expression exp" part 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 b6fb4b456519..de47b918c4ae 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 @@ -516,10 +516,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite, myLanguageLevel); - boolean applicable12 = isApplicableTo(types2AtSite, method1, myLanguageLevel, varargsPosition, methodSubstitutor1, method2, siteSubstitutor2); + boolean applicable12 = isApplicableTo(types2AtSite, method1, myLanguageLevel, varargsPosition, methodSubstitutor1, method2, siteSubstitutor2.putAll(siteSubstitutor1)); final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, myLanguageLevel); - boolean applicable21 = isApplicableTo(types1AtSite, method2, myLanguageLevel, varargsPosition, methodSubstitutor2, method1, siteSubstitutor1); + boolean applicable21 = isApplicableTo(types1AtSite, method2, myLanguageLevel, varargsPosition, methodSubstitutor2, method1, siteSubstitutor1.putAll(siteSubstitutor2)); if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { final boolean typeArgsApplicable12 = GenericsUtil.isTypeArgumentsApplicable(typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21); @@ -616,24 +616,27 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return parameterType instanceof PsiPrimitiveType ^ isExpressionTypePrimitive; } + /** + * @param siteSubstitutor should contain mapping for both candidates sites to align types in hierarchy + */ private boolean isApplicableTo(@NotNull PsiType[] types2AtSite, @NotNull PsiMethod method1, - @NotNull final LanguageLevel languageLevel, + @NotNull LanguageLevel languageLevel, boolean varargsPosition, @NotNull PsiSubstitutor methodSubstitutor1, @NotNull PsiMethod method2, - final PsiSubstitutor siteSubstitutor1) { + PsiSubstitutor siteSubstitutor) { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && method1.getTypeParameters().length > 0 && myArgumentsList instanceof PsiExpressionList) { final PsiElement parent = myArgumentsList.getParent(); if (parent instanceof PsiCallExpression) { - return InferenceSession.isMoreSpecific(method2, method1, siteSubstitutor1, ((PsiExpressionList)myArgumentsList).getExpressions(), myArgumentsList, varargsPosition); + return InferenceSession.isMoreSpecific(method2, method1, siteSubstitutor, ((PsiExpressionList)myArgumentsList).getExpressions(), myArgumentsList, varargsPosition); } } final PsiUtil.ApplicabilityChecker applicabilityChecker = (left, right, allowUncheckedConversion, argId) -> { if (right instanceof PsiClassType) { final PsiClass rightClass = ((PsiClassType)right).resolve(); if (rightClass instanceof PsiTypeParameter) { - right = new PsiImmediateClassType(rightClass, siteSubstitutor1); + right = new PsiImmediateClassType(rightClass, siteSubstitutor); } } return languageLevel.isAtLeast(LanguageLevel.JDK_1_8) ? isTypeMoreSpecific(left, right, argId) : TypeConversionUtil.isAssignable(left, right, allowUncheckedConversion); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/FixedContainingClassTypeArguments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/FixedContainingClassTypeArguments.java new file mode 100644 index 000000000000..9ca65af90622 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/FixedContainingClassTypeArguments.java @@ -0,0 +1,13 @@ +class MyTest { + + static class Foo { + void test(X x) { } + } + static class Bar extends Foo { + void test(Double x) { } + + void call() { + test(null); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/OverloadResolutionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/OverloadResolutionTest.java index 62ff66bdcb9a..4bc4a5c1ff8a 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/OverloadResolutionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/OverloadResolutionTest.java @@ -276,6 +276,7 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase { public void testUnqualifiedStaticInterfaceMethodCallsOnInnerClasses() { doTest(false);} public void testStaticMethodInSuperInterfaceConflictWithCurrentStatic() { doTest(false);} + public void testFixedContainingClassTypeArguments() { doTest(false);} public void testPotentialCompatibilityWithArrayCreation() { doTest(false);} public void testOverloadsWithOneNonCompatible() { doTest(false);} public void testSecondSearchOverloadsBoxing() {