overload resolution: ensure type parameters of containing class are fixed during most specific inference (IDEA-205886)

GitOrigin-RevId: 01b3a6f25c68e27475a053c74a7765e84147beca
This commit is contained in:
Anna Kozlova
2019-06-06 15:57:14 +02:00
committed by intellij-monorepo-bot
parent e530259307
commit b540bb262e
4 changed files with 24 additions and 22 deletions

View File

@@ -1637,14 +1637,7 @@ public class InferenceSession {
PsiElement context,
boolean varargs) {
List<PsiTypeParameter> 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<PsiTypeParameter> 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

View File

@@ -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);

View File

@@ -0,0 +1,13 @@
class MyTest {
static class Foo<X> {
<T> void test(X x) { }
}
static class Bar extends Foo<Integer> {
void test(Double x) { }
void call() {
test<error descr="Ambiguous method call: both 'Bar.test(Double)' and 'Foo.test(Integer)' match">(null)</error>;
}
}
}

View File

@@ -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() {