summaryrefslogtreecommitdiff
path: root/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java')
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java314
1 files changed, 166 insertions, 148 deletions
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
index 27e34f00a25f..35db6c29bc0c 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
@@ -15,10 +15,12 @@
*/
package com.intellij.psi.impl.source.resolve.graphInference;
+import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.*;
@@ -42,8 +44,14 @@ public class InferenceSession {
public static final Key<PsiType> LOWER_BOUND = Key.create("LowBound");
private static final Key<Boolean> ERASED = Key.create("UNCHECKED_CONVERSION");
+ private static final Function<Pair<PsiType, PsiType>, PsiType> UPPER_BOUND_FUNCTION = new Function<Pair<PsiType, PsiType>, PsiType>() {
+ @Override
+ public PsiType fun(Pair<PsiType, PsiType> pair) {
+ return GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
+ }
+ };
- private final Map<PsiTypeParameter, InferenceVariable> myInferenceVariables = new LinkedHashMap<PsiTypeParameter, InferenceVariable>();
+ private final Set<InferenceVariable> myInferenceVariables = new LinkedHashSet<InferenceVariable>();
private final List<ConstraintFormula> myConstraints = new ArrayList<ConstraintFormula>();
private final Set<ConstraintFormula> myConstraintsCopy = new HashSet<ConstraintFormula>();
@@ -56,8 +64,14 @@ public class InferenceSession {
private final InferenceIncorporationPhase myIncorporationPhase = new InferenceIncorporationPhase(this);
private final PsiElement myContext;
-
- private final PsiTypeParameter[] myParamsToInfer;
+
+ private PsiSubstitutor myInferenceSubstitution = PsiSubstitutor.EMPTY;
+ private Map<PsiElement, InferenceSession> myNestedSessions = new HashMap<PsiElement, InferenceSession>();
+ public void registerNestedSession(InferenceSession session) {
+ propagateVariables(session.getInferenceVariables());
+ myNestedSessions.put(session.getContext(), session);
+ myNestedSessions.putAll(session.myNestedSessions);
+ }
public InferenceSession(PsiTypeParameter[] typeParams,
PsiType[] leftTypes,
@@ -70,13 +84,12 @@ public class InferenceSession {
myContext = context;
initBounds(typeParams);
- myParamsToInfer = typeParams;
LOG.assertTrue(leftTypes.length == rightTypes.length);
for (int i = 0; i < leftTypes.length; i++) {
final PsiType rightType = mySiteSubstitutor.substitute(rightTypes[i]);
if (rightType != null) {
- addConstraint(new TypeCompatibilityConstraint(leftTypes[i], rightType));
+ addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(leftTypes[i]), substituteWithInferenceVariables(rightType)));
}
}
}
@@ -90,11 +103,6 @@ public class InferenceSession {
myContext = context;
initBounds(typeParams);
- myParamsToInfer = typeParams;
- }
-
- public PsiTypeParameter[] getParamsToInfer() {
- return myParamsToInfer;
}
public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod method) {
@@ -117,7 +125,7 @@ public class InferenceSession {
for (int i = 0; i < args.length; i++) {
if (args[i] != null && isPertinentToApplicability(args[i], method)) {
PsiType parameterType = getParameterType(parameters, i, mySiteSubstitutor, varargs);
- addConstraint(new ExpressionCompatibilityConstraint(args[i], parameterType));
+ addConstraint(new ExpressionCompatibilityConstraint(args[i], substituteWithInferenceVariables(parameterType)));
}
}
}
@@ -213,7 +221,7 @@ public class InferenceSession {
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
if (!repeatInferencePhases(true)) {
//inferred result would be checked as candidate won't be applicable
- return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
+ return resolveSubset(myInferenceVariables, mySiteSubstitutor);
}
if (properties != null && !properties.isApplicabilityCheck()) {
@@ -235,20 +243,17 @@ public class InferenceSession {
}
}
- final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor);
+ final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, mySiteSubstitutor);
if (substitutor != null) {
if (myContext != null) {
myContext.putUserData(ERASED, myErased);
}
mySiteSubstitutor = substitutor;
- for (PsiTypeParameter parameter : substitutor.getSubstitutionMap().keySet()) {
- final InferenceVariable variable = getInferenceVariable(parameter);
- if (variable != null) {
- variable.setInstantiation(substitutor.substitute(parameter));
- }
+ for (InferenceVariable variable : myInferenceVariables) {
+ variable.setInstantiation(substitutor.substitute(variable.getParameter()));
}
} else {
- return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
+ return resolveSubset(myInferenceVariables, mySiteSubstitutor);
}
return prepareSubstitution();
@@ -262,12 +267,16 @@ public class InferenceSession {
boolean varargs, boolean toplevel) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
- PsiType parameterType = getParameterType(parameters, i, siteSubstitutor, varargs);
+ InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(args[i], PsiCallExpression.class));
+ if (session == null) {
+ session = this;
+ }
+ PsiType parameterType = session.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs));
if (!isPertinentToApplicability(args[i], parentMethod)) {
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
- if (args[i] instanceof PsiCallExpression) {
+ if (args[i] instanceof PsiCallExpression && PsiPolyExpressionUtil.isPolyExpression(args[i])) {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
@@ -299,18 +308,18 @@ public class InferenceSession {
return callExpression.resolveMethodGenerics();
}
};
- final JavaResolveResult result = expression == null
+ MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
+ final JavaResolveResult result = properties != null ? null :
+ expression == null
? computableResolve.compute()
: PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
- if (result instanceof MethodCandidateInfo) {
- final PsiMethod method = ((MethodCandidateInfo)result).getElement();
- //need to get type parameters for 2 level nested expressions (they won't be covered by expression constraints on this level?!)
- initBounds(method.getTypeParameters());
+ final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null;
+ if (method != null) {
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
- collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(),
- additionalConstraints, ((MethodCandidateInfo)result).isVarargs(), false);
+ collectAdditionalConstraints(newParams, newArgs, method, result != null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : properties.getSubstitutor(),
+ additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs(), false);
}
}
}
@@ -321,14 +330,14 @@ public class InferenceSession {
for (InferenceVariable variable : variables) {
final PsiType equalsBound = getEqualsBound(variable, substitutor);
if (!(equalsBound instanceof PsiPrimitiveType)) {
- substitutor = substitutor.put(variable.getParameter(), equalsBound);
+ substitutor = substitutor.put(variable, equalsBound);
}
}
return substitutor;
}
private PsiSubstitutor prepareSubstitution() {
- for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
+ for (InferenceVariable inferenceVariable : myInferenceVariables) {
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation == PsiType.NULL) {
@@ -340,33 +349,24 @@ 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) {
+ initBounds(myContext, typeParameters);
}
- public boolean initBounds(PsiTypeParameter... typeParameters) {
- return initBounds(myContext, typeParameters);
- }
-
- public boolean initBounds(PsiElement context, PsiTypeParameter... typeParameters) {
- boolean sameMethodCall = false;
+ public InferenceVariable[] initBounds(PsiElement context, PsiTypeParameter... typeParameters) {
+ List<InferenceVariable> result = new ArrayList<InferenceVariable>(typeParameters.length);
for (PsiTypeParameter parameter : typeParameters) {
- if (myInferenceVariables.containsKey(parameter)) {
- sameMethodCall = true;
- continue;
- }
InferenceVariable variable = new InferenceVariable(context, parameter);
+ result.add(variable);
+ myInferenceSubstitution = myInferenceSubstitution.put(parameter,
+ JavaPsiFacade.getElementFactory(variable.getProject()).createType(variable));
+ }
+ for (InferenceVariable variable : result) {
+ PsiTypeParameter parameter = variable.getParameter();
boolean added = false;
final PsiClassType[] extendsListTypes = parameter.getExtendsListTypes();
for (PsiType classType : extendsListTypes) {
- classType = mySiteSubstitutor.substitute(classType);
+ classType = substituteWithInferenceVariables(mySiteSubstitutor.substitute(classType));
if (isProperType(classType)) {
added = true;
}
@@ -376,9 +376,9 @@ public class InferenceSession {
variable.addBound(PsiType.getJavaLangObject(parameter.getManager(), parameter.getResolveScope()),
InferenceBound.UPPER);
}
- myInferenceVariables.put(parameter, variable);
}
- return sameMethodCall;
+ myInferenceVariables.addAll(result);
+ return result.toArray(new InferenceVariable[result.size()]);
}
private void initReturnTypeConstraint(PsiMethod method, final PsiCallExpression context) {
@@ -393,7 +393,7 @@ public class InferenceSession {
}
for (PsiClassType thrownType : method.getThrowsList().getReferencedTypes()) {
- final InferenceVariable variable = getInferenceVariable(thrownType);
+ final InferenceVariable variable = getInferenceVariable(substituteWithInferenceVariables(thrownType));
if (variable != null) {
variable.setThrownBound();
}
@@ -401,6 +401,7 @@ public class InferenceSession {
}
public void registerReturnTypeConstraints(PsiType returnType, PsiType targetType) {
+ returnType = substituteWithInferenceVariables(returnType);
final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType);
if (inferenceVariable != null) {
final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor);
@@ -416,17 +417,9 @@ public class InferenceSession {
if (psiClass != null) {
LOG.assertTrue(returnType instanceof PsiClassType);
final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
- PsiSubstitutor subst = PsiSubstitutor.EMPTY;
- final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiClass.getProject());
- PsiTypeParameter[] copy = new PsiTypeParameter[typeParameters.length];
- for (int i = 0; i < typeParameters.length; i++) {
- PsiTypeParameter typeParameter = typeParameters[i];
- copy[i] = elementFactory.createTypeParameterFromText("rCopy" + typeParameter.getName(), null);
- initBounds(myContext, copy[i]);
- subst = subst.put(typeParameter, elementFactory.createType(copy[i]));
- }
- final PsiType substitutedCapture = PsiUtil.captureToplevelWildcards(subst.substitute(returnType), myContext);
- myIncorporationPhase.addCapture(copy, (PsiClassType)returnType);
+ InferenceVariable[] copy = initBounds(myContext, typeParameters);
+ final PsiType substitutedCapture = PsiUtil.captureToplevelWildcards(returnType, myContext);
+ myIncorporationPhase.addCapture(copy, (PsiClassType)substituteWithInferenceVariables(returnType));
addConstraint(new TypeCompatibilityConstraint(targetType, substitutedCapture));
}
} else {
@@ -584,8 +577,8 @@ public class InferenceSession {
public InferenceVariable getInferenceVariable(PsiType psiType) {
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(psiType);
- if (psiClass instanceof PsiTypeParameter) {
- return myInferenceVariables.get(psiClass);
+ if (psiClass instanceof InferenceVariable) {
+ return (InferenceVariable)psiClass;
}
return null;
}
@@ -694,7 +687,13 @@ public class InferenceSession {
while (!allVars.isEmpty()) {
final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this);
if (!myIncorporationPhase.hasCaptureConstraints(vars)) {
- final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
+ PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
+ if (firstSubstitutor != null) {
+ final Set<PsiTypeParameter> parameters = firstSubstitutor.getSubstitutionMap().keySet();
+ if (GenericsUtil.findTypeParameterWithBoundError(parameters.toArray(new PsiTypeParameter[parameters.size()]), firstSubstitutor, myContext, true) != null) {
+ firstSubstitutor = null;
+ }
+ }
if (firstSubstitutor != null) {
substitutor = firstSubstitutor;
allVars.removeAll(vars);
@@ -703,73 +702,102 @@ public class InferenceSession {
}
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
- for (InferenceVariable var : vars) {
- final PsiTypeParameter parameter = var.getParameter();
- 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(var.getCallContext(), copy);
- zVariable.addBound(glb, InferenceBound.UPPER);
+ final PsiTypeParameter[] freshParameters = createFreshVariables(vars);
+ for (int i = 0; i < freshParameters.length; i++) {
+ PsiTypeParameter parameter = freshParameters[i];
+ final InferenceVariable var = vars.get(i);
+ final PsiType lub = getLowerBound(var, PsiSubstitutor.EMPTY);
if (lub != PsiType.NULL) {
- if (!TypeConversionUtil.isAssignable(glb, lub)) {
- return null;
+ for (PsiClassType upperBoundType : parameter.getExtendsListTypes()) {
+ if (!TypeConversionUtil.isAssignable(upperBoundType, lub)) {
+ return null;
+ }
}
- copy.putUserData(LOWER_BOUND, lub);
- zVariable.addBound(lub, InferenceBound.LOWER);
+ parameter.putUserData(LOWER_BOUND, lub);
}
- myInferenceVariables.put(copy, zVariable);
- allVars.add(zVariable);
- var.addBound(elementFactory.createType(copy), InferenceBound.EQ);
+ var.addBound(elementFactory.createType(parameter), InferenceBound.EQ);
}
myIncorporationPhase.forgetCaptures(vars);
- if (!myIncorporationPhase.incorporate()) {
+ if (!repeatInferencePhases(true)) {
return null;
}
}
return substitutor;
}
- private PsiType getLowerBound(InferenceVariable var, PsiSubstitutor substitutor) {
- return composeBound(var, InferenceBound.LOWER, new Function<Pair<PsiType, PsiType>, PsiType>() {
+ private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars) {
+ final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
+
+ PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
+ final PsiTypeParameter[] yVars = new PsiTypeParameter[vars.size()];
+ for (int i = 0; i < vars.size(); i++) {
+ InferenceVariable var = vars.get(i);
+ final PsiTypeParameter parameter = var.getParameter();
+ yVars[i] = elementFactory.createTypeParameterFromText(getFreshVariableName(var), parameter);
+ substitutor = substitutor.put(var, elementFactory.createType(yVars[i]));
+ }
+
+
+ final PsiSubstitutor ySubstitutor = substitutor;
+ final String classText = "class I<" + StringUtil.join(vars, new Function<InferenceVariable, String>() {
@Override
- public PsiType fun(Pair<PsiType, PsiType> pair) {
- return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager);
- }
- }, substitutor);
+ public String fun(InferenceVariable variable) {
+ final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true);
+ return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText();
+ }
+ }, ", ") + ">{}";
+
+ final PsiFile file =
+ PsiFileFactory.getInstance(getManager().getProject()).createFileFromText("inference_dummy.java", JavaFileType.INSTANCE, classText);
+ LOG.assertTrue(file instanceof PsiJavaFile, classText);
+ final PsiClass[] classes = ((PsiJavaFile)file).getClasses();
+ LOG.assertTrue(classes.length == 1, classText);
+ return classes[0].getTypeParameters();
+ }
+
+ private static String getFreshVariableName(InferenceVariable var) {
+ return var.getName();
}
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) {
for (InferenceVariable var : vars) {
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
final PsiTypeParameter typeParameter = var.getParameter();
+ if (substitutor.getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
+ continue;//todo
+ }
+
final PsiType eqBound = getEqualsBound(var, substitutor);
if (eqBound != PsiType.NULL && eqBound instanceof PsiPrimitiveType) continue;
- final PsiType lub = eqBound != PsiType.NULL && (myErased || eqBound != null) ? eqBound : getLowerBound(var, substitutor);
- if (lub != PsiType.NULL) {
- substitutor = substitutor.put(typeParameter, lub);
- }
- else if (var.isThrownBound() && isThrowable(var.getBounds(InferenceBound.UPPER))) {
- final PsiClassType runtimeException = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
- substitutor = substitutor.put(typeParameter, runtimeException);
- }
- else {
- if (substitutor.getSubstitutionMap().get(typeParameter) != null) continue;
- substitutor = substitutor.put(typeParameter, myErased ? null : getUpperBound(var, substitutor));
+ PsiType type = eqBound != PsiType.NULL && (myErased || eqBound != null) ? eqBound : getLowerBound(var, substitutor);
+ if (type == PsiType.NULL) {
+ if (var.isThrownBound() && isThrowable(var.getBounds(InferenceBound.UPPER))) {
+ type = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
+ }
+ else {
+ if (substitutor.getSubstitutionMap().get(typeParameter) != null) continue;
+ type = myErased ? null : getUpperBound(var, substitutor);
+ }
}
+ substitutor = substitutor.put(typeParameter, type);
}
return substitutor;
}
- private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) {
- return composeBound(var, InferenceBound.UPPER, new Function<Pair<PsiType, PsiType>, PsiType>() {
+ private PsiType getLowerBound(InferenceVariable var, PsiSubstitutor substitutor) {
+ return composeBound(var, InferenceBound.LOWER, new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
- return GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
+ return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager);
}
}, substitutor);
}
+ private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) {
+ return composeBound(var, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, substitutor);
+ }
+
public PsiType getEqualsBound(InferenceVariable var, PsiSubstitutor substitutor) {
return composeBound(var, InferenceBound.EQ, new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
@@ -783,16 +811,19 @@ public class InferenceSession {
InferenceBound boundType,
Function<Pair<PsiType, PsiType>, PsiType> fun,
PsiSubstitutor substitutor) {
+ return composeBound(variable, boundType, fun, substitutor, false);
+ }
+
+ private PsiType composeBound(InferenceVariable variable,
+ InferenceBound boundType,
+ Function<Pair<PsiType, PsiType>, PsiType> fun,
+ PsiSubstitutor substitutor,
+ boolean includeNonProperBounds) {
final List<PsiType> lowerBounds = variable.getBounds(boundType);
PsiType lub = PsiType.NULL;
- List<PsiType> dTypes = new ArrayList<PsiType>();
for (PsiType lowerBound : lowerBounds) {
lowerBound = substituteNonProperBound(lowerBound, substitutor);
- final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
- collectDependencies(lowerBound, dependencies);
- if (dependencies.size() == 1 && dependencies.contains(variable) && isInsideRecursiveCall(dependencies)) {
- lub = JavaPsiFacade.getElementFactory(myManager.getProject()).createType(variable.getParameter());
- } else if (dependencies.isEmpty() || isInsideRecursiveCall(dependencies)) {
+ if (includeNonProperBounds || isProperType(lowerBound)) {
if (lub == PsiType.NULL) {
lub = lowerBound;
}
@@ -804,13 +835,6 @@ public class InferenceSession {
return lub;
}
- private boolean isInsideRecursiveCall(HashSet<InferenceVariable> dependencies) {
- for (InferenceVariable dependency : dependencies) {
- if (!isInsideRecursiveCall(dependency.getParameter())) return false;
- }
- return true;
- }
-
public PsiManager getManager() {
return myManager;
}
@@ -820,7 +844,7 @@ public class InferenceSession {
}
public Collection<InferenceVariable> getInferenceVariables() {
- return myInferenceVariables.values();
+ return myInferenceVariables;
}
public void addConstraint(ConstraintFormula constraint) {
@@ -829,10 +853,6 @@ public class InferenceSession {
}
}
- public Collection<PsiTypeParameter> getTypeParams() {
- return myInferenceVariables.keySet();
- }
-
private boolean proceedWithAdditionalConstraints(Set<ConstraintFormula> additionalConstraints) {
final PsiSubstitutor siteSubstitutor = mySiteSubstitutor;
@@ -855,7 +875,7 @@ public class InferenceSession {
}
//resolve input variables
- PsiSubstitutor substitutor = resolveSubset(varsToResolve, retrieveNonPrimitiveEqualsBounds(getInferenceVariables()).putAll(siteSubstitutor));
+ PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor);
if (substitutor == null) {
return false;
}
@@ -972,7 +992,7 @@ public class InferenceSession {
for (int i = 0; i < functionalMethodParameters.length; i++) {
final PsiType pType = signature.getParameterTypes()[i];
- addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs),
+ addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs)),
PsiImplUtil.normalizeWildcardTypeByPosition(pType, reference)));
}
}
@@ -1003,11 +1023,11 @@ public class InferenceSession {
final PsiType qType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, psiSubstitutor);
- addConstraint(new TypeCompatibilityConstraint(qType, pType));
+ addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(qType), pType));
for (int i = 0; i < signature.getParameterTypes().length - 1; i++) {
final PsiType interfaceParamType = signature.getParameterTypes()[i + 1];
- addConstraint(new TypeCompatibilityConstraint(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs),
+ addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(getParameterType(parameters, i, PsiSubstitutor.EMPTY, varargs)),
PsiImplUtil.normalizeWildcardTypeByPosition(interfaceParamType, reference)));
}
}
@@ -1020,7 +1040,7 @@ public class InferenceSession {
}
public InferenceVariable getInferenceVariable(PsiTypeParameter parameter) {
- return myInferenceVariables.get(parameter);
+ return parameter instanceof InferenceVariable && myInferenceVariables.contains(parameter) ? (InferenceVariable)parameter : null;
}
/**
@@ -1031,10 +1051,11 @@ public class InferenceSession {
PsiExpression[] args,
PsiElement context,
boolean varargs) {
- final InferenceSession session = new InferenceSession(PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY, m2.getManager(), context);
+ List<PsiTypeParameter> params = new ArrayList<PsiTypeParameter>();
for (PsiTypeParameter param : PsiUtil.typeParametersIterable(m2)) {
- session.initBounds(context, param);
+ params.add(param);
}
+ final InferenceSession session = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), PsiSubstitutor.EMPTY, m2.getManager(), context);
final PsiParameter[] parameters1 = m1.getParameterList().getParameters();
final PsiParameter[] parameters2 = m2.getParameterList().getParameters();
@@ -1045,7 +1066,7 @@ public class InferenceSession {
final int paramsLength = !varargs ? parameters1.length : parameters1.length - 1;
for (int i = 0; i < paramsLength; i++) {
PsiType sType = getParameterType(parameters1, i, PsiSubstitutor.EMPTY, false);
- PsiType tType = getParameterType(parameters2, i, PsiSubstitutor.EMPTY, varargs);
+ PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, i, PsiSubstitutor.EMPTY, varargs));
if (session.isProperType(sType) && session.isProperType(tType)) {
if (!TypeConversionUtil.isAssignable(tType, sType)) {
return false;
@@ -1063,7 +1084,7 @@ public class InferenceSession {
if (varargs) {
PsiType sType = getParameterType(parameters1, paramsLength, PsiSubstitutor.EMPTY, true);
- PsiType tType = getParameterType(parameters2, paramsLength, PsiSubstitutor.EMPTY, true);
+ PsiType tType = session.substituteWithInferenceVariables(getParameterType(parameters2, paramsLength, PsiSubstitutor.EMPTY, true));
session.addConstraint(new StrictSubtypingConstraint(tType, sType));
}
@@ -1257,25 +1278,6 @@ public class InferenceSession {
return myIncorporationPhase.hasCaptureConstraints(Arrays.asList(inferenceVariable));
}
- public void liftBounds(PsiElement context, Collection<InferenceVariable> variables) {
- for (InferenceVariable variable : variables) {
- final PsiTypeParameter parameter = variable.getParameter();
- final InferenceVariable inferenceVariable = getInferenceVariable(parameter);
- if (inferenceVariable != null) {
- final PsiElement callContext = inferenceVariable.getCallContext();
- if (context.equals(callContext) || myContext.equals(callContext)) {
- for (InferenceBound boundType : InferenceBound.values()) {
- for (PsiType bound : variable.getBounds(boundType)) {
- inferenceVariable.addBound(bound, boundType);
- }
- }
- }
- } else {
- myInferenceVariables.put(parameter, variable);
- }
- }
- }
-
public static boolean wasUncheckedConversionPerformed(PsiElement call) {
final Boolean erased = call.getUserData(ERASED);
return erased != null && erased.booleanValue();
@@ -1284,4 +1286,20 @@ public class InferenceSession {
public PsiElement getContext() {
return myContext;
}
+
+ public void propagateVariables(Collection<InferenceVariable> variables) {
+ myInferenceVariables.addAll(variables);
+ }
+
+ public PsiType substituteWithInferenceVariables(PsiType type) {
+ return myInferenceSubstitution.substitute(type);
+ }
+
+ public PsiType startWithFreshVars(PsiType type) {
+ PsiSubstitutor s = PsiSubstitutor.EMPTY;
+ for (InferenceVariable variable : myInferenceVariables) {
+ s = s.put(variable, JavaPsiFacade.getElementFactory(variable.getProject()).createType(variable.getParameter()));
+ }
+ return s.substitute(type);
+ }
}