new inference: reject partial computation

This commit is contained in:
Anna Kozlova
2014-02-21 18:55:54 +01:00
parent 72c51dc1b8
commit 2f80e7d9c0
6 changed files with 64 additions and 45 deletions
@@ -376,14 +376,6 @@ public class LambdaUtil {
final int lambdaIdx = getLambdaIdx(expressionList, expression);
if (lambdaIdx > -1) {
PsiType cachedType = null;
final Pair<PsiMethod, PsiSubstitutor> method = MethodCandidateInfo.getCurrentMethod(parent);
if (method != null) {
final PsiParameter[] parameters = method.first.getParameterList().getParameters();
cachedType = lambdaIdx < parameters.length ? method.second.substitute(getNormalizedType(parameters[adjustLambdaIdx(lambdaIdx, method.first, parameters)])) : null;
if (!tryToSubstitute) return cachedType;
}
PsiElement gParent = expressionList.getParent();
if (gParent instanceof PsiAnonymousClass) {
@@ -399,22 +391,6 @@ public class LambdaUtil {
final int finalLambdaIdx = adjustLambdaIdx(lambdaIdx, (PsiMethod)resolve, parameters);
if (finalLambdaIdx < parameters.length) {
if (!tryToSubstitute) return getNormalizedType(parameters[finalLambdaIdx]);
if (cachedType != null) {
final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(cachedType);
if (interfaceMethod != null) {
final PsiClassType.ClassResolveResult cachedResult = PsiUtil.resolveGenericsClassInType(cachedType);
if (paramIdx == -1) {
if (!dependsOnTypeParams(cachedType, cachedType, expression) && !dependsOnTypeParams(getFunctionalInterfaceReturnType(cachedType), cachedType, expression)) {
return cachedType;
}
}
else {
if (!dependsOnTypeParams(cachedResult.getSubstitutor().substitute(interfaceMethod.getParameterList().getParameters()[paramIdx].getType()), cachedType, expression)) {
return cachedType;
}
}
}
}
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
@@ -15,7 +15,6 @@
*/
package com.intellij.psi.impl.source.resolve.graphInference.constraints;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable;
@@ -78,9 +77,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (myExpression instanceof PsiCallExpression) {
final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList();
if (argumentList != null) {
final Pair<PsiMethod,PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList);
final JavaResolveResult resolveResult = pair == null ? ((PsiCallExpression)myExpression).resolveMethodGenerics() : null;
final PsiMethod method = pair != null ? pair.first : (PsiMethod)resolveResult.getElement();
final JavaResolveResult resolveResult = ((PsiCallExpression)myExpression).resolveMethodGenerics();
final PsiMethod method = (PsiMethod)resolveResult.getElement();
PsiType returnType = null;
PsiTypeParameter[] typeParams = null;
if (method != null && !method.isConstructor()) {
@@ -105,21 +103,18 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
session.addCapturedVariable(typeParam);
}
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
if (pair == null) {
if (method != null) {
//typeParams are already included
final Collection<PsiTypeParameter> params = session.getTypeParams();
InferenceSession callSession = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), myExpression.getManager(), myExpression);
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method);
callSession.registerConstraints(returnType, myT);
if (callSession.repeatInferencePhases(true)) {
session.liftBounds(callSession.getInferenceVariables());
}
if (method != null) {
//typeParams are already included
final Collection<PsiTypeParameter> params = session.getTypeParams();
InferenceSession callSession = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), resolveResult instanceof MethodCandidateInfo ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor()
: PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression);
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method);
callSession.registerConstraints(returnType, myT);
if (callSession.repeatInferencePhases(true)) {
session.liftBounds(callSession.getInferenceVariables());
}
} else {
substitutor = pair.second;
}
final PsiType capturedReturnType = myExpression instanceof PsiMethodCallExpression
? PsiMethodCallExpressionImpl.captureReturnType((PsiMethodCallExpression)myExpression, method, returnType, substitutor)
@@ -1,8 +1,8 @@
class IntStream {
private void foo(IntStream s) {
s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> 1 << i)</error>;
s.map(i -> <error descr="Operator '<<' cannot be applied to 'int', '<lambda parameter>'">1 << i</error>);
s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> 1)</error>;
s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Integer>)' match">(i -> i)</error>;
s.map<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<T>)' match">(i -> i)</error>;
}
public static void main(String[] args) {
@@ -25,7 +25,7 @@ class ReturnTypeIncompatibility {
}
public static void main(String[] args) {
call<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Integer>)' and 'ReturnTypeIncompatibility.call(I2<P>)' match">(i-> {return i;})</error>;
call<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<P>)' and 'ReturnTypeIncompatibility.call(I2<P>)' match">(i-> {return i;})</error>;
}
}
@@ -0,0 +1,44 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collector;
class Stuff {
public enum Type { A }
private final int value;
private final Type type;
public Stuff(int value, Type type) {
this.value = value;
this.type = type;
}
public int getValue() {
return value;
}
public Type getType() {
return type;
}
}
class FakeErrors {
{
Collector<Stuff, ?, Map<Stuff.Type, Optional<Stuff>>> collector =
groupingBy(Stuff::getType,
reducing((d1, d2) -> {
boolean b = d1.getValue() > d2.getValue();
return d1;
}));
}
public static <T> Collector<T, ?, Optional<Stuff>> reducing(BinaryOperator<T> op) {
return null;
}
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return null;
}
}
@@ -126,6 +126,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIDEA119535() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}