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 | 314 |
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); + } } |