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.java169
1 files changed, 144 insertions, 25 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 dba4a7289a5e..df785073a6d7 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
@@ -18,13 +18,17 @@ package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
+import com.intellij.psi.impl.PsiImplUtil;
+import com.intellij.psi.impl.source.resolve.graphInference.constraints.CheckedExceptionCompatibilityConstraint;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.ConstraintFormula;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.ExpressionCompatibilityConstraint;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeCompatibilityConstraint;
import com.intellij.psi.infos.MethodCandidateInfo;
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,7 +42,6 @@ public class InferenceSession {
private Map<PsiTypeParameter, InferenceVariable> myInferenceVariables = new LinkedHashMap<PsiTypeParameter, InferenceVariable>();
private final List<ConstraintFormula> myConstraints = new ArrayList<ConstraintFormula>();
- private final List<ConstraintFormula> myDelayedConstraints = new ArrayList<ConstraintFormula>();
private PsiSubstitutor mySiteSubstitutor;
private PsiManager myManager;
@@ -46,6 +49,10 @@ public class InferenceSession {
private final InferenceIncorporationPhase myIncorporationPhase = new InferenceIncorporationPhase(this);
+ public InferenceSession(PsiSubstitutor siteSubstitutor) {
+ mySiteSubstitutor = siteSubstitutor;
+ }
+
public InferenceSession(PsiTypeParameter[] typeParams,
PsiType[] leftTypes,
PsiType[] rightTypes,
@@ -75,14 +82,10 @@ public class InferenceSession {
if (parameters.length > 0) {
for (int i = 0; i < args.length; i++) {
- PsiType parameterType = mySiteSubstitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType());
- if (parameterType instanceof PsiEllipsisType) {
- if (args.length != parameters.length || args[i] != null && !(args[i].getType() instanceof PsiArrayType)) {
- parameterType = ((PsiEllipsisType)parameterType).getComponentType();
- }
- }
+ PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor);
if (args[i] != null) {
myConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
+ //myConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
}
}
}
@@ -98,11 +101,66 @@ public class InferenceSession {
}
}
+ public static boolean isPertinentToApplicability(PsiExpression expr, PsiMethod method) {
+ if (expr instanceof PsiLambdaExpression) {
+ if (((PsiLambdaExpression)expr).hasFormalParameterTypes()) return true;
+ for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)expr)) {
+ if (!isPertinentToApplicability(expression, method)) return false;
+ }
+ if (method.getTypeParameters().length > 0) {
+ final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expr.getParent());
+ if (parent instanceof PsiExpressionList) {
+ final PsiElement gParent = parent.getParent();
+ if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArgumentList().getTypeParameterElements().length == 0) {
+ final int idx = LambdaUtil.getLambdaIdx(((PsiExpressionList)parent), expr);
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ PsiType paramType;
+ if (idx > parameters.length - 1) {
+ final PsiType lastParamType = parameters[parameters.length - 1].getType();
+ paramType = parameters[parameters.length - 1].isVarArgs() ? ((PsiEllipsisType)lastParamType).getComponentType() : lastParamType;
+ }
+ else {
+ paramType = parameters[idx].getType();
+ }
+ final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(paramType);
+ if (psiClass instanceof PsiTypeParameter && ((PsiTypeParameter)psiClass).getOwner() == method) return false;
+ }
+ }
+ }
+ return true;
+ }
+ if (expr instanceof PsiMethodReferenceExpression) {
+ return ((PsiMethodReferenceExpression)expr).isExact();
+ }
+ if (expr instanceof PsiParenthesizedExpression) {
+ return isPertinentToApplicability(((PsiParenthesizedExpression)expr).getExpression(), method);
+ }
+ if (expr instanceof PsiConditionalExpression) {
+ final PsiExpression thenExpression = ((PsiConditionalExpression)expr).getThenExpression();
+ if (!isPertinentToApplicability(thenExpression, method)) return false;
+ final PsiExpression elseExpression = ((PsiConditionalExpression)expr).getElseExpression();
+ if (!isPertinentToApplicability(elseExpression, method)) return false;
+ }
+ return true;
+ }
+
+ private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, PsiSubstitutor substitutor) {
+ PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType());
+ if (parameterType instanceof PsiEllipsisType) {
+ if (args.length != parameters.length || PsiPolyExpressionUtil
+ .isPolyExpression(args[i]) || args[i] != null && !(args[i].getType() instanceof PsiArrayType)) {
+ parameterType = ((PsiEllipsisType)parameterType).getComponentType();
+ }
+ }
+ return parameterType;
+ }
+
@NotNull
public PsiSubstitutor infer() {
repeatInferencePhases();
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
+ if (inferenceVariable.isCaptured()) continue;
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation == PsiType.NULL) {
@@ -136,25 +194,60 @@ public class InferenceSession {
}
}
}
+
+ public void addCapturedVariable(PsiTypeParameter param) {
+ if (myInferenceVariables.containsKey(param)) return; //same method call
+ final InferenceVariable variable = new InferenceVariable(param);
+ variable.setCaptured(true);
+ myInferenceVariables.put(param, variable);
+ }
private void initReturnTypeConstraint(PsiMethod method, PsiCallExpression context) {
if (PsiPolyExpressionUtil.isPolyExpression(context) ||
context instanceof PsiNewExpression && PsiDiamondType.ourDiamondGuard.currentStack().contains(context)) {
final PsiType returnType = method.getReturnType();
if (!PsiType.VOID.equals(returnType) && returnType != null) {
- final PsiType targetType = PsiPolyExpressionUtil.getTargetType(context);//todo primitive type
+ PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context);
+ if (targetType == null) {
+ final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent());
+ if (parent instanceof PsiExpressionList) {
+ final PsiElement gParent = parent.getParent();
+ if (gParent instanceof PsiCallExpression) {
+ final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList();
+ if (argumentList != null) {
+ final JavaResolveResult resolveResult = ((PsiCallExpression)gParent).resolveMethodGenerics();
+ final PsiElement parentMethod = resolveResult.getElement();
+ if (parentMethod instanceof PsiMethod) {
+ final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters();
+ PsiElement arg = context;
+ while (arg.getParent() instanceof PsiParenthesizedExpression) {
+ arg = parent.getParent();
+ }
+ final PsiExpression[] args = argumentList.getExpressions();
+ targetType = getParameterType(parameters, args, ArrayUtilRt.find(args, arg), resolveResult.getSubstitutor());
+ }
+ }
+ }
+ } else if (parent instanceof PsiConditionalExpression) {
+ targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent);
+ }
+ }
if (targetType != null) {
- myConstraints.add(new TypeCompatibilityConstraint(targetType, returnType));
+ myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context)));
}
}
}
}
public InferenceVariable getInferenceVariable(PsiType psiType) {
+ return getInferenceVariable(psiType, true);
+ }
+
+ public InferenceVariable getInferenceVariable(PsiType psiType, boolean acceptCaptured) {
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(psiType);
if (psiClass instanceof PsiTypeParameter) {
final InferenceVariable inferenceVariable = myInferenceVariables.get(psiClass);
- if (inferenceVariable != null) {
+ if (inferenceVariable != null && (acceptCaptured || !inferenceVariable.isCaptured())) {
return inferenceVariable;
}
}
@@ -162,10 +255,16 @@ public class InferenceSession {
}
public boolean isProperType(@Nullable PsiType type) {
- return collectDependencies(type, null);
+ return isProperType(type, true);
}
- public boolean collectDependencies(@Nullable PsiType type, @Nullable final Set<InferenceVariable> dependencies) {
+ public boolean isProperType(@Nullable PsiType type, boolean acceptCaptured) {
+ return collectDependencies(type, null, acceptCaptured);
+ }
+
+ public boolean collectDependencies(@Nullable PsiType type,
+ @Nullable final Set<InferenceVariable> dependencies,
+ final boolean acceptCaptured) {
if (type == null) return true;
final Boolean isProper = type.accept(new PsiTypeVisitor<Boolean>() {
@Nullable
@@ -191,7 +290,7 @@ public class InferenceSession {
@Nullable
@Override
public Boolean visitClassType(PsiClassType classType) {
- final InferenceVariable inferenceVariable = getInferenceVariable(classType);
+ final InferenceVariable inferenceVariable = getInferenceVariable(classType, acceptCaptured);
if (inferenceVariable != null) {
if (dependencies != null) {
dependencies.add(inferenceVariable);
@@ -225,7 +324,7 @@ public class InferenceSession {
List<ConstraintFormula> newConstraints = new ArrayList<ConstraintFormula>();
for (int i = myConstraintIdx; i < myConstraints.size(); i++) {
ConstraintFormula constraint = myConstraints.get(i);
- if (!constraint.reduce(this, newConstraints, myDelayedConstraints)) {
+ if (!constraint.reduce(this, newConstraints)) {
return false;
}
}
@@ -241,7 +340,7 @@ public class InferenceSession {
for (List<InferenceVariable> variables : independentVars) {
for (InferenceVariable inferenceVariable : variables) {
- if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
+ if (inferenceVariable.isCaptured() || inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
try {
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
@@ -253,19 +352,18 @@ public class InferenceSession {
}
PsiType bound = null;
for (PsiType eqBound : eqBounds) {
- eqBound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound);
- if (isProperType(eqBound)) {
- bound = eqBound;
- break;
- }
+ bound = acceptBoundsWithRecursiveDependencies(typeParameter, eqBound);
}
if (bound != null) {
+ if (bound instanceof PsiCapturedWildcardType && eqBounds.size() > 1) {
+ continue;
+ }
inferenceVariable.setInstantiation(bound);
} else {
PsiType lub = null;
for (PsiType lowerBound : lowerBounds) {
lowerBound = acceptBoundsWithRecursiveDependencies(typeParameter, lowerBound);
- if (isProperType(lowerBound)) {
+ if (isProperType(lowerBound, false)) {
if (lub == null) {
lub = lowerBound;
}
@@ -281,7 +379,7 @@ public class InferenceSession {
PsiType glb = null;
for (PsiType upperBound : upperBounds) {
upperBound = acceptBoundsWithRecursiveDependencies(typeParameter, upperBound);
- if (isProperType(upperBound)) {
+ if (isProperType(upperBound, false)) {
if (glb == null) {
glb = upperBound;
}
@@ -307,8 +405,9 @@ public class InferenceSession {
}
private PsiType acceptBoundsWithRecursiveDependencies(PsiTypeParameter typeParameter, PsiType bound) {
- if (PsiPolyExpressionUtil.mentionsTypeParameters(bound, Collections.singleton(typeParameter))) {
- return mySiteSubstitutor.put(typeParameter, null).substitute(bound);
+ if (!isProperType(bound)) {
+ final PsiSubstitutor substitutor = PsiUtil.resolveClassInType(bound) != typeParameter ? mySiteSubstitutor.put(typeParameter, null) : mySiteSubstitutor;
+ return substitutor.substitute(bound);
}
return bound;
}
@@ -330,4 +429,24 @@ public class InferenceSession {
myConstraints.add(constraint);
}
}
+
+ public Collection<PsiTypeParameter> getTypeParams() {
+ return myInferenceVariables.keySet();
+ }
+
+ public void addVariable(PsiTypeParameter typeParameter, final PsiType parameter) {
+ InferenceVariable variable = new InferenceVariable(typeParameter);
+ if (parameter instanceof PsiWildcardType) {
+ PsiType bound = ((PsiWildcardType)parameter).getBound();
+ if (bound != null) {
+ variable.addBound(bound, ((PsiWildcardType)parameter).isExtends() ? InferenceBound.UPPER : InferenceBound.LOWER);
+ } else {
+ variable.addBound(PsiType.getJavaLangObject(typeParameter.getManager(), parameter.getResolveScope()),
+ InferenceBound.UPPER);
+ }
+ } else {
+ variable.addBound(parameter, InferenceBound.EQ);
+ }
+ myInferenceVariables.put(typeParameter, variable);
+ }
}