overload resolution: reject more specific inference contradicting site substitution

This commit is contained in:
Anna Kozlova
2015-08-25 16:14:03 +03:00
parent 29370f178d
commit 98408c72f6
4 changed files with 36 additions and 9 deletions

View File

@@ -1335,6 +1335,7 @@ public class InferenceSession {
*/
public static boolean isMoreSpecific(PsiMethod m1,
PsiMethod m2,
PsiSubstitutor siteSubstitutor1,
PsiExpression[] args,
PsiElement context,
boolean varargs) {
@@ -1342,7 +1343,10 @@ public class InferenceSession {
for (PsiTypeParameter param : PsiUtil.typeParametersIterable(m2)) {
params.add(param);
}
final InferenceSession session = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), PsiSubstitutor.EMPTY, m2.getManager(), context);
siteSubstitutor1 = getSiteSubstitutor(siteSubstitutor1, params);
final InferenceSession session = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), siteSubstitutor1, m2.getManager(), context);
final PsiParameter[] parameters1 = m1.getParameterList().getParameters();
final PsiParameter[] parameters2 = m2.getParameterList().getParameters();
@@ -1352,8 +1356,8 @@ public class InferenceSession {
final int paramsLength = !varargs ? parameters1.length : parameters1.length - 1;
for (int i = 0; i < paramsLength; i++) {
PsiType sType = getParameterType(parameters1, i, PsiSubstitutor.EMPTY, false);
PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, i, PsiSubstitutor.EMPTY, varargs));
PsiType sType = getParameterType(parameters1, i, siteSubstitutor1, false);
PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, i, siteSubstitutor1, varargs));
if (LambdaUtil.isFunctionalType(sType) && LambdaUtil.isFunctionalType(tType) && !relates(sType, tType)) {
if (!isFunctionalTypeMoreSpecific(sType, tType, session, args[i])) {
return false;
@@ -1369,14 +1373,22 @@ public class InferenceSession {
}
if (varargs) {
PsiType sType = getParameterType(parameters1, paramsLength, PsiSubstitutor.EMPTY, true);
PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, paramsLength, PsiSubstitutor.EMPTY, true));
PsiType sType = getParameterType(parameters1, paramsLength, siteSubstitutor1, true);
PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, paramsLength, siteSubstitutor1, true));
session.addConstraint(new StrictSubtypingConstraint(tType, sType));
}
return session.repeatInferencePhases(true);
}
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

@@ -544,10 +544,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
final PsiSubstitutor methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, method1, siteSubstitutor1, types1, types2AtSite,
languageLevel);
boolean applicable12 = isApplicableTo(types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2);
boolean applicable12 = isApplicableTo(types2AtSite, method1, languageLevel, varargsPosition, methodSubstitutor1, method2, siteSubstitutor2);
final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, method2, siteSubstitutor2, types2, types1AtSite, languageLevel);
boolean applicable21 = isApplicableTo(types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1);
boolean applicable21 = isApplicableTo(types1AtSite, method2, languageLevel, varargsPosition, methodSubstitutor2, method1, siteSubstitutor1);
if (!myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
final boolean typeArgsApplicable12 = GenericsUtil.isTypeArgumentsApplicable(typeParameters1, methodSubstitutor1, myArgumentsList, !applicable21);
@@ -641,11 +641,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
@NotNull LanguageLevel languageLevel,
boolean varargsPosition,
@NotNull PsiSubstitutor methodSubstitutor1,
@NotNull PsiMethod method2) {
@NotNull PsiMethod method2,
PsiSubstitutor siteSubstitutor1) {
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, ((PsiExpressionList)myArgumentsList).getExpressions(), myArgumentsList, varargsPosition);
return InferenceSession.isMoreSpecific(method2, method1, siteSubstitutor1, ((PsiExpressionList)myArgumentsList).getExpressions(), myArgumentsList, varargsPosition);
}
}
final PsiUtil.ApplicabilityChecker applicabilityChecker = languageLevel.isAtLeast(LanguageLevel.JDK_1_8)

View File

@@ -0,0 +1,10 @@
class Test {
interface One<T> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
}
static One<String> foo;
public static void main(String[] args) throws Exception {
foo.save <error descr="Ambiguous method call: both 'One.save(String)' and 'One.save(Iterable<String>)' match">(null)</error>;
}
}

View File

@@ -126,6 +126,10 @@ public class MostSpecificResolutionTest extends LightDaemonAnalyzerTestCase {
doTest(false);
}
public void testIncompatibleSiteSubstitutionBounds() throws Exception {
doTest(false);
}
private void doTest() {
doTest(true);
}