diff options
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.java | 169 |
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); + } } |