new inference: support for nested same method calls

This commit is contained in:
Anna Kozlova
2014-02-27 15:29:30 +01:00
parent fa6672f721
commit 5dd7e0622c
6 changed files with 59 additions and 40 deletions

View File

@@ -389,21 +389,4 @@ public class InferenceIncorporationPhase {
}
}
}
public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor, Collection<InferenceVariable> variables) {
for (InferenceVariable variable : variables) { //todo equals bounds?
for (PsiType lowerBound : variable.getBounds(InferenceBound.LOWER)) {
lowerBound = substitutor.substitute(lowerBound);
if (mySession.isProperType(lowerBound)) {
for (PsiType upperBound : variable.getBounds(InferenceBound.UPPER)) {
upperBound = substitutor.substitute(upperBound);
if (mySession.isProperType(upperBound) && !TypeConversionUtil.isAssignable(upperBound, lowerBound)) {
return null;
}
}
}
}
}
return substitutor;
}
}

View File

@@ -208,7 +208,7 @@ public class InferenceSession {
PsiMethod parentMethod) {
if (!repeatInferencePhases(true)) {
//inferred result would be checked as candidate won't be applicable
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
}
if (parentMethod != null) {
@@ -294,7 +294,7 @@ public class InferenceSession {
}
}
} else {
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
}
return prepareSubstitution();
@@ -386,7 +386,7 @@ public class InferenceSession {
public void registerConstraints(PsiType returnType, PsiType targetType) {
final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType);
if (inferenceVariable != null) {
final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true);
final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor);
myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutor.substitute(inferenceVariable.getParameter()), myContext)));
}
else {
@@ -529,12 +529,13 @@ public class InferenceSession {
}
final int i = ArrayUtilRt.find(args, arg);
if (i < 0) return null;
return getParameterType(parameters, args, i, PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false, new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
return result.getSubstitutor();
}
}));
return getParameterType(parameters, args, i, PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false,
new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
return result.getSubstitutor();
}
}));
}
return null;
}
@@ -657,7 +658,7 @@ public class InferenceSession {
while (!allVars.isEmpty()) {
final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this);
if (!myIncorporationPhase.hasCaptureConstraints(vars)) {
final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, true);
final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
if (firstSubstitutor != null) {
substitutor = firstSubstitutor;
allVars.removeAll(vars);
@@ -668,7 +669,7 @@ public class InferenceSession {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
for (InferenceVariable var : vars) {
final PsiTypeParameter parameter = var.getParameter();
final PsiTypeParameter copy = elementFactory.createTypeParameterFromText(parameter.getName(), null);
final PsiTypeParameter copy = elementFactory.createTypeParameterFromText("z" + parameter.getName(), null);
final PsiType lub = getLowerBound(var, substitutor);
final PsiType glb = getUpperBound(var, substitutor);
final InferenceVariable zVariable = new InferenceVariable(copy);
@@ -681,6 +682,8 @@ public class InferenceSession {
zVariable.addBound(lub, InferenceBound.LOWER);
}
myInferenceVariables.put(copy, zVariable);
allVars.add(zVariable);
var.addBound(elementFactory.createType(copy), InferenceBound.EQ);
}
myIncorporationPhase.forgetCaptures(vars);
if (!myIncorporationPhase.incorporate()) {
@@ -699,7 +702,7 @@ public class InferenceSession {
}, substitutor);
}
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor, boolean checkResult) {
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) {
for (InferenceVariable var : vars) {
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
final PsiTypeParameter typeParameter = var.getParameter();
@@ -718,7 +721,7 @@ public class InferenceSession {
}
}
return checkResult ? myIncorporationPhase.checkIncorporated(substitutor, vars) : substitutor;
return substitutor;
}
private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) {
@@ -809,7 +812,7 @@ public class InferenceSession {
}
//resolve input variables
PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor, true);
PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor);
if (substitutor == null) {
return false;

View File

@@ -22,6 +22,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil
import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -99,14 +100,28 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
if (typeParams != null) {
for (PsiTypeParameter typeParam : typeParams) {
session.addCapturedVariable(typeParam);
}
session.initBounds(typeParams);
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
//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 HashSet<InferenceVariable> variables = new HashSet<InferenceVariable>();
session.collectDependencies(returnType, variables);
final PsiTypeParameter[] params = new PsiTypeParameter[typeParams.length];
for (int i = 0; i < typeParams.length; i++) {
if (variables.contains(session.getInferenceVariable(typeParams[i]))) {
params[i] = JavaPsiFacade.getElementFactory(myExpression.getProject()).createTypeParameterFromText("copyOf" + myExpression.hashCode() + typeParams[i].getName(), null);
substitutor = substitutor.put(typeParams[i], JavaPsiFacade.getElementFactory(myExpression.getProject()).createType(params[i]));
}
else {
params[i] = typeParams[i];
}
}
final PsiSubstitutor siteSubstitutor = resolveResult instanceof MethodCandidateInfo ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY;
for (PsiTypeParameter typeParameter : siteSubstitutor.getSubstitutionMap().keySet()) {
substitutor = substitutor.put(typeParameter, substitutor.substitute(siteSubstitutor.substitute(typeParameter)));
}
final Collection<PsiTypeParameter> params1 = session.getTypeParams();
final InferenceSession callSession = new InferenceSession(params1.toArray(new PsiTypeParameter[params1.size()]), substitutor, myExpression.getManager(), myExpression);
callSession.initBounds(params);
if (method != null) {
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();

View File

@@ -109,6 +109,11 @@ public class TypeEqualityConstraint implements ConstraintFormula {
return true;
}
if (myT instanceof PsiCapturedWildcardType && myS instanceof PsiCapturedWildcardType) {
return new TypeEqualityConstraint(((PsiCapturedWildcardType)myT).getWildcard(),
((PsiCapturedWildcardType)myS).getWildcard()).reduce(session, constraints);
}
return false;
}

View File

@@ -1,3 +1,16 @@
import java.util.List;
class Main0 {
<T> List<T> foo(T t){
return null;
}
{
foo(foo(""));
}
}
class Main {
static <T> T foo(T t) { return null; }
@@ -14,6 +27,6 @@ class Main1 {
static <B> B bar(B t) { return null;}
static {
long l = foo(bar(1));
//long l = foo(bar(1));
}
}

View File

@@ -28,7 +28,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void _testNestedCallsSameMethod() throws Exception {
public void testNestedCallsSameMethod() throws Exception {
doTest();
}