lambda: use incomplete substitutor when calc functional interface (IDEA-97038)

This commit is contained in:
anna
2012-12-18 19:29:02 +01:00
parent e94f80bd20
commit bd4346cea8
5 changed files with 52 additions and 15 deletions

View File

@@ -18,6 +18,7 @@ package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.infos.MethodCandidateInfo;
@@ -396,11 +397,11 @@ public class LambdaUtil {
if (lambdaIdx > -1) {
if (!tryToSubstitute) {
final Map<PsiElement, PsiMethod> currentMethodCandidates = MethodCandidateInfo.CURRENT_CANDIDATE.get();
final PsiMethod method = currentMethodCandidates != null ? currentMethodCandidates.get(parent) : null;
final Map<PsiElement,Pair<PsiMethod,PsiSubstitutor>> currentMethodCandidates = MethodCandidateInfo.CURRENT_CANDIDATE.get();
final Pair<PsiMethod, PsiSubstitutor> method = currentMethodCandidates != null ? currentMethodCandidates.get(parent) : null;
if (method != null) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
return lambdaIdx < parameters.length ? parameters[lambdaIdx].getType() : null;
final PsiParameter[] parameters = method.first.getParameterList().getParameters();
return lambdaIdx < parameters.length ? method.second.substitute(parameters[lambdaIdx].getType()) : null;
}
}
@@ -579,8 +580,14 @@ public class LambdaUtil {
if (parent instanceof PsiExpressionList) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCall) {
final Map<PsiElement, PsiMethod> map = MethodCandidateInfo.CURRENT_CANDIDATE.get();
myMethod = map != null ? map.get(parent) : null;
final Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>> map = MethodCandidateInfo.CURRENT_CANDIDATE.get();
if (map != null) {
final Pair<PsiMethod, PsiSubstitutor> pair = map.get(parent);
myMethod = pair != null ? pair.first : null;
}
else {
myMethod = null;
}
if (myMethod == null) {
myMethod = ((PsiCall)gParent).resolveMethod();
}

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.psi.infos;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
@@ -31,7 +32,7 @@ import java.util.Set;
* @author ik, dsl
*/
public class MethodCandidateInfo extends CandidateInfo{
public static final ThreadLocal<Map<PsiElement, PsiMethod>> CURRENT_CANDIDATE = new ThreadLocal<Map<PsiElement, PsiMethod>>();
public static final ThreadLocal<Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>>> CURRENT_CANDIDATE = new ThreadLocal<Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>>>();
@ApplicabilityLevelConstant private int myApplicabilityLevel = 0;
private final PsiElement myArgumentList;
private final PsiType[] myArgumentTypes;
@@ -96,15 +97,15 @@ public class MethodCandidateInfo extends CandidateInfo{
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
PsiMethod method = getElement();
if (myTypeArguments == null) {
Map<PsiElement, PsiMethod> map;
Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>> map;
synchronized (LOCK) {
map = CURRENT_CANDIDATE.get();
if (map == null) {
map = new ConcurrentWeakHashMap<PsiElement, PsiMethod>();
map = new ConcurrentWeakHashMap<PsiElement, Pair<PsiMethod, PsiSubstitutor>>();
CURRENT_CANDIDATE.set(map);
}
}
map.put(myArgumentList, getElement());
map.put(myArgumentList, Pair.create(getElement(), incompleteSubstitutor));
try {
final Set<PsiParameterList> lists = LambdaUtil.ourParams.get();

View File

@@ -588,14 +588,14 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
final PsiElement parent = skipParenthesizedExprUp(lambdaExpression.getParent());
if (parent instanceof PsiExpressionList) {
final PsiExpressionList expressionList = (PsiExpressionList)parent;
final Map<PsiElement,PsiMethod> methodMap = MethodCandidateInfo.CURRENT_CANDIDATE.get();
final PsiMethod method = methodMap != null ? methodMap.get(expressionList) : null;
if (method != null) {
final Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>> methodMap = MethodCandidateInfo.CURRENT_CANDIDATE.get();
final Pair<PsiMethod, PsiSubstitutor> pair = methodMap != null ? methodMap.get(expressionList) : null;
if (pair != null) {
final int i = LambdaUtil.getLambdaIdx(expressionList, lambdaExpression);
if (i < 0) return null;
final PsiParameter[] parameters = method.getParameterList().getParameters();
final PsiParameter[] parameters = pair.first.getParameterList().getParameters();
if (parameters.length <= i) return null;
return inferConstraintFromFunctionalInterfaceMethod(typeParam, lambdaExpression, parameters[i].getType(), lowerBound);
return inferConstraintFromFunctionalInterfaceMethod(typeParam, lambdaExpression, pair.second.substitute(parameters[i].getType()), lowerBound);
}
}
else {

View File

@@ -0,0 +1,25 @@
import java.util.concurrent.atomic.AtomicInteger;
class Test {
static class List<T> {
public Stream<T> stream() {
return null;
}
}
interface IntFunction<T> {
public int applyAsInt(T t);
}
static class Stream<E> {
public Stream map(IntFunction<? super E> mapper) {
return null;
}
}
public static void main(List<AtomicInteger> list) {
list.stream().map(atomic -> atomic.get());
}
}

View File

@@ -169,6 +169,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testUseIncompleteParentSubstitutor() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}