new inference: open/close capture when method reference is resolved (IDEA-128712)

This commit is contained in:
Anna Kozlova
2014-08-18 20:56:11 +04:00
parent f39bfa7af0
commit 356c3e7c9e
5 changed files with 46 additions and 17 deletions
@@ -75,20 +75,22 @@ public class PsiMethodReferenceUtil {
return null;
}
public static boolean isCorrectAssignment(PsiType[] signatureParameterTypes2,
PsiType[] parameterTypes,
public static boolean isCorrectAssignment(PsiType[] parameterTypes,
PsiType[] argTypes,
boolean varargs,
int offset) {
final int min = Math.min(signatureParameterTypes2.length, parameterTypes.length - offset);
final int min = Math.min(parameterTypes.length, argTypes.length - offset);
for (int i = 0; i < min; i++) {
final PsiType type1 = parameterTypes[i + offset];
final PsiType type2 = signatureParameterTypes2[i];
if (varargs && i == signatureParameterTypes2.length - 1) {
if (!TypeConversionUtil.isAssignable(type2, type1) && !TypeConversionUtil.isAssignable(((PsiArrayType)type2).getComponentType(), type1)) {
final PsiType argType = argTypes[i + offset];
PsiType parameterType = parameterTypes[i];
parameterType = GenericsUtil.getVariableTypeByExpressionType(parameterType, true);
if (varargs && i == parameterTypes.length - 1) {
if (!TypeConversionUtil.isAssignable(parameterType, argType) &&
!TypeConversionUtil.isAssignable(((PsiArrayType)parameterType).getComponentType(), argType)) {
return false;
}
}
else if (!TypeConversionUtil.isAssignable(type2, type1)) {
else if (!TypeConversionUtil.isAssignable(parameterType, argType)) {
return false;
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.*;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.search.GlobalSearchScope;
@@ -784,6 +785,7 @@ public class InferenceSession {
PsiSubstitutor substitutor) {
final List<PsiType> lowerBounds = variable.getBounds(boundType);
PsiType lub = PsiType.NULL;
List<PsiType> dTypes = new ArrayList<PsiType>();
for (PsiType lowerBound : lowerBounds) {
lowerBound = substituteNonProperBound(lowerBound, substitutor);
final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
@@ -970,7 +972,8 @@ public class InferenceSession {
for (int i = 0; i < functionalMethodParameters.length; i++) {
final PsiType pType = signature.getParameterTypes()[i];
addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs), pType));
addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs),
PsiImplUtil.normalizeWildcardTypeByPosition(pType, reference)));
}
}
else if (parameters.length + 1 == functionalMethodParameters.length && !varargs ||
@@ -1004,7 +1007,8 @@ public class InferenceSession {
for (int i = 0; i < signature.getParameterTypes().length - 1; i++) {
final PsiType interfaceParamType = signature.getParameterTypes()[i + 1];
addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs), interfaceParamType));
addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs),
PsiImplUtil.normalizeWildcardTypeByPosition(interfaceParamType, reference)));
}
}
@@ -231,8 +231,8 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
checkSameSignatures(conflicts);
checkAccessStaticLevels(conflicts, true);
final PsiType[] parameterTypes = mySignature.getParameterTypes();
boolean hasReceiver = PsiMethodReferenceUtil.hasReceiver(parameterTypes, myQualifierResolveResult, myReferenceExpression);
final PsiType[] argTypes = mySignature.getParameterTypes();
boolean hasReceiver = PsiMethodReferenceUtil.hasReceiver(argTypes, myQualifierResolveResult, myReferenceExpression);
final List<CandidateInfo> firstCandidates = new ArrayList<CandidateInfo>();
final List<CandidateInfo> secondCandidates = new ArrayList<CandidateInfo>();
@@ -242,19 +242,19 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
final PsiSubstitutor substitutor = conflict.getSubstitutor();
final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(substitutor).getParameterTypes();
final PsiType[] parameterTypes = psiMethod.getSignature(substitutor).getParameterTypes();
final boolean varargs = ((MethodCandidateInfo)conflict).isVarargs();
if (varargs && (!psiMethod.isVarArgs() || myFunctionalMethodVarArgs)) continue;
if ((varargs || parameterTypes.length == signatureParameterTypes2.length) &&
PsiMethodReferenceUtil.isCorrectAssignment(signatureParameterTypes2, parameterTypes, varargs, 0)) {
if ((varargs || argTypes.length == parameterTypes.length) &&
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 0)) {
firstCandidates.add(conflict);
}
if (hasReceiver &&
(varargs || parameterTypes.length == signatureParameterTypes2.length + 1) &&
PsiMethodReferenceUtil.isCorrectAssignment(signatureParameterTypes2, parameterTypes, varargs, 1)) {
(varargs || argTypes.length == parameterTypes.length + 1) &&
PsiMethodReferenceUtil.isCorrectAssignment(parameterTypes, argTypes, varargs, 1)) {
secondCandidates.add(conflict);
}
}
@@ -0,0 +1,19 @@
import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Stream;
abstract class Foo {
{
map(Foo::bar);
map(a -> Foo.bar(a));
}
<R> Stream<R> map(Function<Class<?>, ? extends R> mapper) {
return null;
}
private static <T> Collection<T> bar(Class<T> baseClass) {
return null;
}
}
@@ -301,6 +301,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA128712() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}