new inference: nothing should be cached during overload resolution (IDEA-136759)

This commit is contained in:
Anna Kozlova
2015-02-24 19:00:41 +01:00
parent 1de1e949f4
commit e63a2de86f
8 changed files with 111 additions and 49 deletions

View File

@@ -116,48 +116,36 @@ public class MethodCandidateInfo extends CandidateInfo{
return getApplicabilityLevel();
}
@ApplicabilityLevelConstant int level;
Integer boxedLevel = ourOverloadGuard.doPreventingRecursion(myArgumentList, false, new Computable<Integer>() {
@Override
public Integer compute() {
if (PsiUtil.isLanguageLevel8OrHigher(myArgumentList)) {
PsiSubstitutor substitutor = getSubstitutor(false);
Map<PsiElement, CurrentCandidateProperties> map = CURRENT_CANDIDATE.get();
if (map == null) {
map = ContainerUtil.createConcurrentWeakMap();
CURRENT_CANDIDATE.set(map);
}
final PsiMethod method = getElement();
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
try {
PsiType[] argumentTypes = getArgumentTypes();
if (argumentTypes == null) {
return ApplicabilityLevel.NOT_APPLICABLE;
}
final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
if (!isVarargs() && applicabilityLevel < ApplicabilityLevel.FIXED_ARITY) {
return ApplicabilityLevel.NOT_APPLICABLE;
}
return applicabilityLevel;
}
finally {
if (alreadyThere == null) {
map.remove(getMarkerList());
} else {
map.put(getMarkerList(), alreadyThere);
}
}
}
return getApplicabilityLevelInner();
PsiSubstitutor substitutor = getSubstitutor(false);
Map<PsiElement, CurrentCandidateProperties> map = CURRENT_CANDIDATE.get();
if (map == null) {
map = ContainerUtil.createConcurrentWeakMap();
CURRENT_CANDIDATE.set(map);
}
final PsiMethod method = getElement();
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
try {
PsiType[] argumentTypes = getArgumentTypes();
if (argumentTypes == null) {
return ApplicabilityLevel.NOT_APPLICABLE;
}
});
if (boxedLevel == null) {
return getApplicabilityLevel();
level = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
if (!isVarargs() && level < ApplicabilityLevel.FIXED_ARITY) {
return ApplicabilityLevel.NOT_APPLICABLE;
}
}
finally {
if (alreadyThere == null) {
map.remove(getMarkerList());
} else {
map.put(getMarkerList(), alreadyThere);
}
}
if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) {
level = ApplicabilityLevel.NOT_APPLICABLE;
}
level = boxedLevel;
if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) level = ApplicabilityLevel.NOT_APPLICABLE;
return level;
}

View File

@@ -396,8 +396,17 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
}
};
if (!varargs && staticFactoryMethod.isVarArgs() && staticFactoryCandidateInfo.getPertinentApplicabilityLevel() < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
if (!varargs && staticFactoryMethod.isVarArgs()) {
final Computable<Integer> computable = new Computable<Integer>() {
@Override
public Integer compute() {
return staticFactoryCandidateInfo.getPertinentApplicabilityLevel();
}
};
final Integer applicability = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(expression, true, computable);
if ((applicability != null ? applicability : staticFactoryCandidateInfo.getApplicabilityLevel()) < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
}
}
return staticFactoryCandidateInfo.getSubstitutor();
}

View File

@@ -16,6 +16,7 @@
package com.intellij.psi.impl.source.tree.java;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.ResolveCache;
@@ -212,7 +213,7 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
@Nullable
@Override
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts) {
protected CandidateInfo guardedOverloadResolution(@NotNull List<CandidateInfo> conflicts) {
if (mySignature == null) return null;
if (conflicts.size() > 1) checkSameSignatures(conflicts);

View File

@@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
@@ -68,7 +69,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
@Override
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts){
public final CandidateInfo resolveConflict(@NotNull final List<CandidateInfo> conflicts){
return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, true, new Computable<CandidateInfo>() {
@Override
public CandidateInfo compute() {
return guardedOverloadResolution(conflicts);
}
});
}
@Nullable
protected CandidateInfo guardedOverloadResolution(@NotNull List<CandidateInfo> conflicts) {
if (conflicts.isEmpty()) return null;
if (conflicts.size() == 1) return conflicts.get(0);

View File

@@ -0,0 +1,19 @@
import java.util.function.Function;
import java.util.stream.Stream;
class Test {
public Long getKey() {
return 0L;
}
public static void main(Stream<Test> stream) {
stream.map(s -> Inner.of(Test::getKey, s));
}
public static final class Inner<K> {
public static <T> Inner<T> of(final Object key, final Test value) {return null;}
public static <T> Inner<T> of(final Function< T, Long> keyMapper, final Test value) {return null;}
}
}

View File

@@ -0,0 +1,19 @@
import java.util.function.Function;
import java.util.stream.Stream;
class Test {
public Long getKey() {
return 0L;
}
public static void main(Stream<Test> stream) {
stream.map(s -> Inner.of(Test::get<ref>Key, s));
}
public static final class Inner<K> {
public static <T> Inner<T> of(final Object key, final Test value) {return null;}
public static <T> Inner<T> of(final Function< T, Long> keyMapper, final Test value) {return null;}
}
}

View File

@@ -17,14 +17,13 @@ package com.intellij.codeInsight.daemon.lambda;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
import com.intellij.idea.Bombed;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NonNls;
import java.util.Calendar;
public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
@NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/newLambda";
@@ -178,6 +177,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA136759() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}
@@ -194,7 +197,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
/*
public static Test suite() {
final TestSuite suite = new TestSuite();
for (int i = 0; i < 100; i++) {
for (int i = 0; i < 1000; i++) {
suite.addTestSuite(NewLambdaHighlightingTest.class);
}
return suite;

View File

@@ -32,11 +32,15 @@ public class TypeInference18Test extends ResolveTestCase {
}
public void testSecondConflictResolution() throws Exception {
doTestMethodCall();
}
public void testCachedSubstitutionDuringOverloadResolution() throws Exception {
PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
assertNotNull(ref);
PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodCallExpression.class);
PsiMethodReferenceExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodReferenceExpression.class, false);
assertNotNull(methodCallExpression);
assertNotNull(methodCallExpression.resolveMethod());
assertNotNull(methodCallExpression.resolve());
}
private LanguageLevel myOldLanguageLevel;
@@ -55,6 +59,14 @@ public class TypeInference18Test extends ResolveTestCase {
super.tearDown();
}
private void doTestMethodCall() throws Exception {
PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
assertNotNull(ref);
PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodCallExpression.class);
assertNotNull(methodCallExpression);
assertNotNull(methodCallExpression.resolveMethod());
}
private void doTest() throws Exception {
PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
assertNotNull(ref);