new inference: use available in stack methods, do not cache if this info was used (IDEA-122406)

This commit is contained in:
Anna Kozlova
2014-03-26 18:54:41 +01:00
parent a4f36f237c
commit c7eb840149
8 changed files with 173 additions and 8 deletions
@@ -180,7 +180,10 @@ public class MethodCandidateInfo extends CandidateInfo{
final PsiSubstitutor inferredSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE, includeReturnConstraint);
if (!stackStamp.mayCacheNow() || !ourOverloadGuard.currentStack().isEmpty() || !includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
if (!stackStamp.mayCacheNow() ||
!ourOverloadGuard.currentStack().isEmpty() ||
!includeReturnConstraint && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) ||
getMarkerList() != null && PsiResolveHelper.ourGraphGuard.currentStack().contains(getMarkerList().getParent())) {
return inferredSubstitutor;
}
@@ -16,6 +16,7 @@
package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.psi.*;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.Nullable;
@@ -58,7 +59,8 @@ public class PsiPolyExpressionUtil {
}
}
} else if (expression instanceof PsiMethodCallExpression) {
return isMethodCallPolyExpression(expression, ((PsiMethodCallExpression)expression).resolveMethod());
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(((PsiMethodCallExpression)expression).getArgumentList());
return isMethodCallPolyExpression(expression, candidateProperties != null ? candidateProperties.getMethod() : ((PsiMethodCallExpression)expression).resolveMethod());
}
else if (expression instanceof PsiConditionalExpression) {
final ConditionalKind conditionalKind = isBooleanOrNumeric(expression);
@@ -80,8 +80,9 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (myExpression instanceof PsiCallExpression) {
final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList();
if (argumentList != null) {
final JavaResolveResult resolveResult = ((PsiCallExpression)myExpression).resolveMethodGenerics();
final PsiMethod method = (PsiMethod)resolveResult.getElement();
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(((PsiCallExpression)myExpression).getArgumentList());
final JavaResolveResult resolveResult = candidateProperties != null ? null : ((PsiCallExpression)myExpression).resolveMethodGenerics();
final PsiMethod method = candidateProperties != null ? candidateProperties.getMethod() : (PsiMethod)resolveResult.getElement();
PsiType returnType = null;
PsiTypeParameter[] typeParams = null;
if (method != null && !method.isConstructor()) {
@@ -117,8 +118,15 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
params[i] = typeParams[i];
}
}
final PsiSubstitutor siteSubstitutor = resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor()
? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY;
PsiSubstitutor siteSubstitutor = PsiSubstitutor.EMPTY;
if (method != null && !method.isConstructor()) {
if (resolveResult instanceof MethodCandidateInfo) {
siteSubstitutor = ((MethodCandidateInfo)resolveResult).getSiteSubstitutor();
}
else if (candidateProperties != null) {
siteSubstitutor = candidateProperties.getSubstitutor();
}
}
for (PsiTypeParameter typeParameter : siteSubstitutor.getSubstitutionMap().keySet()) {
substitutor = substitutor.put(typeParameter, substitutor.substitute(siteSubstitutor.substitute(typeParameter)));
}
@@ -129,7 +137,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (method != null) {
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method, resolveResult instanceof MethodCandidateInfo && ((MethodCandidateInfo)resolveResult).isVarargs());
callSession.initExpressionConstraints(parameters, args, myExpression, method, resolveResult instanceof MethodCandidateInfo && ((MethodCandidateInfo)resolveResult).isVarargs() ||
candidateProperties != null && candidateProperties.isVarargs());
}
final boolean accepted = callSession.repeatInferencePhases(true);
if (!accepted) {
@@ -18,6 +18,7 @@ package com.intellij.psi.scope.conflictResolvers;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.PsiConflictResolver;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.containers.HashMap;
@@ -47,7 +48,7 @@ public class DuplicateConflictResolver implements PsiConflictResolver{
final PsiElement element = info.getElement();
Object key;
if (element instanceof PsiMethod) {
key = ((PsiMethod)element).getSignature(info.getSubstitutor());
key = ((PsiMethod)element).getSignature(((MethodCandidateInfo)info).getSubstitutor(false));
}
else {
key = PsiUtilCore.getName(element);
@@ -0,0 +1,41 @@
import java.util.*;
import java.util.function.Predicate;
abstract class Test {
public long countTweetsLongerThan(int numberOfChars, final List<String> tweetList) {
//numberOfChars = 100; //TODO uncomment to show it must be effectively final
long totalByFor = 0;
for (String tweet : tweetList) {
if (tweet.length() > numberOfChars) {
totalByFor++;
}
}
final ArrayList<String> guavaList = newArrayList(filter(tweetList, new Predicate<String>() {
@Override
public boolean test(String tweet) {
return false;
}
}));
final long totalFromGuava = guavaList.size();
final long totalFromLambda = tweetList.stream()
.filter(t -> t.length() > numberOfChars)
.count();
if (totalByFor != totalFromLambda | totalByFor != totalFromGuava) {
throw new RuntimeException("");
}
return totalFromLambda;
}
abstract <E> ArrayList<E> newArrayList(Iterable<? extends E> elements);
abstract <E> ArrayList<E> newArrayList();
abstract <E> ArrayList<E> newArrayList(E... elements);
abstract <T> Iterable<T> filter(Iterable<T> unfiltered, Predicate<? super T> predicate);
abstract <T> Iterable<T> filter(Iterable<?> unfiltered, Class<T> type);
}
@@ -0,0 +1,41 @@
import java.util.*;
import java.util.function.Predicate;
abstract class Test {
public long countTweetsLongerThan(int numberOfChars, final List<String> tweetList) {
//numberOfChars = 100; //TODO uncomment to show it must be effectively final
long totalByFor = 0;
for (String tweet : tweetList) {
if (tweet.length() > numberOfChars) {
totalByFor++;
}
}
final ArrayList<String> guavaList = newArrayList(fil<ref>ter(tweetList, new Predicate<String>() {
@Override
public boolean test(String tweet) {
return false;
}
}));
final long totalFromGuava = guavaList.size();
final long totalFromLambda = tweetList.stream()
.filter(t -> t.length() > numberOfChars)
.count();
if (totalByFor != totalFromLambda | totalByFor != totalFromGuava) {
throw new RuntimeException("");
}
return totalFromLambda;
}
abstract <E> ArrayList<E> newArrayList(Iterable<? extends E> elements);
abstract <E> ArrayList<E> newArrayList();
abstract <E> ArrayList<E> newArrayList(E... elements);
abstract <T> Iterable<T> filter(Iterable<T> unfiltered, Predicate<? super T> predicate);
abstract <T> Iterable<T> filter(Iterable<?> unfiltered, Class<T> type);
}
@@ -178,6 +178,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA122406() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}
@@ -0,0 +1,64 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.lambda;
import com.intellij.JavaTestUtil;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.ResolveTestCase;
public class TypeInference18Test extends ResolveTestCase {
public void testIDEA122406() throws Exception {
doTest();
}
private LanguageLevel myOldLanguageLevel;
@Override
protected void setUp() throws Exception {
super.setUp();
myOldLanguageLevel = LanguageLevelProjectExtension.getInstance(myJavaFacade.getProject()).getLanguageLevel();
LanguageLevelProjectExtension.getInstance(myJavaFacade.getProject()).setLanguageLevel(LanguageLevel.JDK_1_8);
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
}
@Override
protected void tearDown() throws Exception {
LanguageLevelProjectExtension.getInstance(myJavaFacade.getProject()).setLanguageLevel(myOldLanguageLevel);
super.tearDown();
}
private void doTest() throws Exception {
PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
assertNotNull(ref);
assertNotNull(ref.resolve());
}
@Override
protected Sdk getTestProjectJdk() {
return IdeaTestUtil.getMockJdk18();
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath();
}
}