graph inference: recursive calls (IDEA-119834)

This commit is contained in:
Anna Kozlova
2014-01-27 19:59:23 +04:00
parent 7942f6c12c
commit c8e5698c54
7 changed files with 54 additions and 12 deletions
@@ -72,7 +72,7 @@ public class FunctionalInterfaceParameterizationUtil {
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod == null) return null;
final InferenceSession session = new InferenceSession(PsiSubstitutor.EMPTY);
final InferenceSession session = new InferenceSession(PsiSubstitutor.EMPTY, expr);
PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
if (typeParameters.length != parameters.length) {
return null;
@@ -29,10 +29,12 @@ import com.intellij.psi.scope.MethodProcessorSetupFailedException;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.ReflectionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,17 +57,22 @@ public class InferenceSession {
private final InferenceIncorporationPhase myIncorporationPhase = new InferenceIncorporationPhase(this);
public InferenceSession(PsiSubstitutor siteSubstitutor) {
private final PsiElement myContext;
public InferenceSession(PsiSubstitutor siteSubstitutor, PsiElement expr) {
mySiteSubstitutor = siteSubstitutor;
myContext = expr;
}
public InferenceSession(PsiTypeParameter[] typeParams,
PsiType[] leftTypes,
PsiType[] rightTypes,
PsiSubstitutor siteSubstitutor,
PsiManager manager) {
PsiManager manager,
PsiElement context) {
myManager = manager;
mySiteSubstitutor = siteSubstitutor;
myContext = context;
initBounds(typeParams);
@@ -80,9 +87,11 @@ public class InferenceSession {
public InferenceSession(PsiTypeParameter[] typeParams,
PsiSubstitutor siteSubstitutor,
PsiManager manager) {
PsiManager manager,
PsiElement context) {
myManager = manager;
mySiteSubstitutor = siteSubstitutor;
myContext = context;
initBounds(typeParams);
}
@@ -252,6 +261,17 @@ public class InferenceSession {
return mySiteSubstitutor;
}
private boolean isInsideRecursiveCall(PsiTypeParameter parameter) {
final PsiTypeParameterListOwner parameterOwner = parameter.getOwner();
if (myContext != null && PsiTreeUtil.isAncestor(parameterOwner, myContext, true)) {
final PsiModifierListOwner staticContainer = PsiUtil.getEnclosingStaticElement(myContext, null);
if (staticContainer == null || PsiTreeUtil.isAncestor(staticContainer, parameterOwner, false)) {
return true;
}
}
return false;
}
public void initBounds(PsiTypeParameter... typeParameters) {
for (PsiTypeParameter parameter : typeParameters) {
if (myInferenceVariables.containsKey(parameter)) continue;
@@ -274,7 +294,6 @@ public class InferenceSession {
}
public void addCapturedVariable(PsiTypeParameter param) {
if (myInferenceVariables.containsKey(param)) return; //same method call
initBounds(param);
}
@@ -549,7 +568,7 @@ public class InferenceSession {
inferred = boundCandidatesNumber > typeParameter.getExtendsListTypes().length && (typeParameter.getExtendsListTypes().length > 0 || boundCandidatesNumber > 1);
}
}
if (glb != null && (acceptInitialUpperBound || inferred)) {
if (glb != null && (acceptInitialUpperBound && !isInsideRecursiveCall(typeParameter) || inferred)) {
inferenceVariable.setInstantiation(glb);
}
}
@@ -38,7 +38,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
@NotNull PsiSubstitutor partialSubstitutor,
@Nullable PsiElement parent,
@NotNull ParameterTypeInferencePolicy policy) {
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager);
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager, parent);
inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
return inferenceSession.infer(parameters, arguments, parent, policy).substitute(typeParameter);
}
@@ -53,7 +53,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
@NotNull ParameterTypeInferencePolicy policy,
@NotNull LanguageLevel languageLevel) {
if (typeParameters.length == 0) return partialSubstitutor;
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, myManager);
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, myManager, parent);
inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
return inferenceSession.infer(parameters, arguments, parent, policy);
}
@@ -65,7 +65,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel) {
if (typeParameters.length == 0) return PsiSubstitutor.EMPTY;
InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager);
InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null);
for (PsiType leftType : leftTypes) {
if (!session.isProperType(leftType)) {
return session.infer();
@@ -104,7 +104,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
leftTypes = new PsiType[] {arg};
rightTypes = new PsiType[]{param};
}
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParam}, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager);
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParam}, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null);
if (inferenceSession.isProperType(param) && inferenceSession.isProperType(arg)) {
boolean proceed = false;
for (PsiClassType classType : typeParam.getExtendsListTypes()) {
@@ -108,7 +108,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
if (pair == null) {
if (method != null) {
InferenceSession callSession = new InferenceSession(typeParams, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), myExpression.getManager());
InferenceSession callSession = new InferenceSession(typeParams, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), myExpression.getManager(), myExpression);
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method);
@@ -12,7 +12,7 @@ class Test1 {
class Test2 {
protected <T, U> U exerciseOps(TestData<T> data, TerminalOp<T, U> terminal, IntermediateOp... ops) {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'U'">return exerciseOps(data, (u, v) -> u.equals(v), terminal);</error>
return exerciseOps(data, (u, v) -> u.equals(v), terminal);
}
}
@@ -0,0 +1,19 @@
public class Bug
{
interface I<K>{}
public static <CRN>I<CRN> create(final I<CRN> it)
{
final I<CRN> f = null;
Bug.<String>create(fn<error descr="'fn(Bug.I<java.lang.String>)' in 'Bug' cannot be applied to '(Bug.I<CRN>)'">(f)</error>);
return create(fn(f));
}
private static <FN>I<FN> fn(final I<FN> f)
{
return null;
}
}
@@ -95,6 +95,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testRecursiveCalls() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}