diff options
Diffstat (limited to 'java/java-psi-impl/src/com/intellij/psi')
14 files changed, 250 insertions, 277 deletions
diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java index da32b64ea092..b8f810611201 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java @@ -204,7 +204,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor { ProgressIndicatorProvider.checkCanceled(); ControlFlowSubRange subRange = entry.getValue(); PsiElement element = entry.getKey(); - myControlFlowFactory.registerSubRange(element, subRange, myEvaluateConstantIfCondition, myPolicy); + myControlFlowFactory.registerSubRange(element, subRange, myEvaluateConstantIfCondition, myEnabledShortCircuit, myPolicy); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java index 2ba1906c422c..3159193bce4f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowFactory.java @@ -62,19 +62,29 @@ public class ControlFlowFactory { cachedFlows.clear(); } + @Deprecated public void registerSubRange(final PsiElement codeFragment, final ControlFlowSubRange flow, final boolean evaluateConstantIfConfition, final ControlFlowPolicy policy) { - registerControlFlow(codeFragment, flow, evaluateConstantIfConfition, policy); + registerSubRange(codeFragment, flow, evaluateConstantIfConfition, true, policy); + } + + public void registerSubRange(final PsiElement codeFragment, + final ControlFlowSubRange flow, + final boolean evaluateConstantIfConfition, + boolean enableShortCircuit, final ControlFlowPolicy policy) { + registerControlFlow(codeFragment, flow, evaluateConstantIfConfition, enableShortCircuit, policy); } private static class ControlFlowContext { private final ControlFlowPolicy policy; private final boolean evaluateConstantIfCondition; + private final boolean enableShortCircuit; private final long modificationCount; private final ControlFlow controlFlow; - private ControlFlowContext(boolean evaluateConstantIfCondition, @NotNull ControlFlowPolicy policy, long modificationCount, @NotNull ControlFlow controlFlow) { + private ControlFlowContext(boolean evaluateConstantIfCondition, boolean enableShortCircuit, @NotNull ControlFlowPolicy policy, long modificationCount, @NotNull ControlFlow controlFlow) { this.evaluateConstantIfCondition = evaluateConstantIfCondition; + this.enableShortCircuit = enableShortCircuit; this.policy = policy; this.modificationCount = modificationCount; this.controlFlow = controlFlow; @@ -96,9 +106,10 @@ public class ControlFlowFactory { return result; } - public boolean isFor(@NotNull ControlFlowPolicy policy, final boolean evaluateConstantIfCondition, long modificationCount) { + public boolean isFor(@NotNull ControlFlowPolicy policy, final boolean evaluateConstantIfCondition, final boolean enableShortCircuit, long modificationCount) { if (modificationCount != this.modificationCount) return false; if (!policy.equals(this.policy)) return false; + if (enableShortCircuit != this.enableShortCircuit) return false; // optimization: when no constant condition were computed, both control flows are the same if (!controlFlow.isConstantConditionOccurred()) return true; @@ -107,7 +118,7 @@ public class ControlFlowFactory { } private boolean isFor(@NotNull ControlFlowContext that) { - return isFor(that.policy, that.evaluateConstantIfCondition, that.modificationCount); + return isFor(that.policy, that.evaluateConstantIfCondition, that.enableShortCircuit, that.modificationCount); } } @@ -129,28 +140,30 @@ public class ControlFlowFactory { final long modificationCount = element.getManager().getModificationTracker().getModificationCount(); ConcurrentList<ControlFlowContext> cached = getOrCreateCachedFlowsForElement(element); for (ControlFlowContext context : cached) { - if (context.isFor(policy, evaluateConstantIfCondition,modificationCount)) return context.controlFlow; + if (context.isFor(policy, evaluateConstantIfCondition, enableShortCircuit, modificationCount)) return context.controlFlow; } ControlFlow controlFlow = new ControlFlowAnalyzer(element, policy, enableShortCircuit, evaluateConstantIfCondition).buildControlFlow(); - ControlFlowContext context = createContext(evaluateConstantIfCondition, policy, controlFlow, modificationCount); + ControlFlowContext context = createContext(evaluateConstantIfCondition, enableShortCircuit, policy, controlFlow, modificationCount); cached.addIfAbsent(context); return controlFlow; } @NotNull private static ControlFlowContext createContext(final boolean evaluateConstantIfCondition, + boolean enableShortCircuit, @NotNull ControlFlowPolicy policy, @NotNull ControlFlow controlFlow, final long modificationCount) { - return new ControlFlowContext(evaluateConstantIfCondition, policy, modificationCount,controlFlow); + return new ControlFlowContext(evaluateConstantIfCondition, enableShortCircuit, policy, modificationCount,controlFlow); } private void registerControlFlow(@NotNull PsiElement element, @NotNull ControlFlow flow, boolean evaluateConstantIfCondition, + boolean enableShortCircuit, @NotNull ControlFlowPolicy policy) { final long modificationCount = element.getManager().getModificationTracker().getModificationCount(); - ControlFlowContext controlFlowContext = createContext(evaluateConstantIfCondition, policy, flow, modificationCount); + ControlFlowContext controlFlowContext = createContext(evaluateConstantIfCondition, enableShortCircuit, policy, flow, modificationCount); ConcurrentList<ControlFlowContext> cached = getOrCreateCachedFlowsForElement(element); cached.addIfAbsent(controlFlowContext); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 7c597e495f2e..9c9525aef859 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -80,14 +80,14 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } private boolean containsInMap(PsiTypeParameter typeParameter) { - if (typeParameter instanceof LightTypeParameter) { + if (typeParameter instanceof LightTypeParameter && ((LightTypeParameter)typeParameter).useDelegateToSubstitute()) { typeParameter = ((LightTypeParameter)typeParameter).getDelegate(); } return mySubstitutionMap.containsKey(typeParameter); } private PsiType getFromMap(@NotNull PsiTypeParameter typeParameter) { - if (typeParameter instanceof LightTypeParameter) { + if (typeParameter instanceof LightTypeParameter && ((LightTypeParameter)typeParameter).useDelegateToSubstitute()) { typeParameter = ((LightTypeParameter)typeParameter).getDelegate(); } return mySubstitutionMap.get(typeParameter); @@ -394,7 +394,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } } } - } else if (substituted instanceof PsiWildcardType && ((PsiWildcardType)substituted).isSuper()) { + } else if (substituted instanceof PsiWildcardType && ((PsiWildcardType)substituted).isSuper() && !(oldSubstituted instanceof PsiCapturedWildcardType)) { final PsiType erasure = TypeConversionUtil.erasure(((PsiWildcardType)substituted).getBound()); if (erasure != null) { final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index c188c3a38013..9129052bf74f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -263,7 +263,6 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this); ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); - final JavaPsiFacade facade = getFacade(); final Condition<String> nameCondition = processor.getHint(JavaCompletionHints.NAME_FILTER); if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) { @@ -291,7 +290,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya for (PsiPackage pack : packs) { final String packageName = pack.getName(); if (packageName == null) continue; - if (!facade.getNameHelper().isIdentifier(packageName, PsiUtil.getLanguageLevel(this))) { + if (!PsiNameHelper.getInstance(myManager.getProject()).isIdentifier(packageName, PsiUtil.getLanguageLevel(this))) { continue; } if (!processor.execute(pack, state)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameter.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameter.java index 6775a64c59ef..3cd347648a07 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameter.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightTypeParameter.java @@ -79,6 +79,10 @@ public class LightTypeParameter extends LightClass implements PsiTypeParameter { return getDelegate().addAnnotation(qualifiedName); } + public boolean useDelegateToSubstitute() { + return true; + } + @Override public String toString() { return "PsiTypeParameter:" + getName(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index b4b188c772cc..9742e0f28608 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -36,7 +36,7 @@ public class FunctionalInterfaceParameterizationUtil { } if (classType instanceof PsiClassType) { for (PsiType type : ((PsiClassType)classType).getParameters()) { - if (type instanceof PsiWildcardType || type instanceof PsiCapturedWildcardType) { + if (type instanceof PsiWildcardType) { return true; } } @@ -94,7 +94,8 @@ public class FunctionalInterfaceParameterizationUtil { final InferenceSession session = new InferenceSession(typeParameters, PsiSubstitutor.EMPTY, expr.getManager(), expr); for (int i = 0; i < targetMethodParams.length; i++) { - session.addConstraint(new TypeEqualityConstraint(lambdaParams[i].getType(), targetMethodParams[i].getType())); + session.addConstraint(new TypeEqualityConstraint(lambdaParams[i].getType(), + session.substituteWithInferenceVariables(targetMethodParams[i].getType()))); } if (!session.repeatInferencePhases(false)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index 9766122e31d0..9c8b8b4772b3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -89,28 +89,6 @@ public class InferenceIncorporationPhase { upDown(lowerBounds, eqBounds, substitutor); upUp(upperBounds); - - for (PsiType eqBound : eqBounds) { - if (mySession.isProperType(eqBound)) { - for (PsiType upperBound : upperBounds) { - if (!mySession.isProperType(upperBound)) { - addConstraint(new StrictSubtypingConstraint(substitutor.substitute(upperBound), eqBound)); - } - } - - for (PsiType lowerBound : lowerBounds) { - if (!mySession.isProperType(lowerBound)) { - addConstraint(new StrictSubtypingConstraint(eqBound, substitutor.substitute(lowerBound))); - } - } - - for (PsiType otherEqBound : eqBounds) { - if (eqBound != otherEqBound && !mySession.isProperType(otherEqBound)) { - addConstraint(new TypeEqualityConstraint(substitutor.substitute(otherEqBound), eqBound)); - } - } - } - } } for (Pair<PsiTypeParameter[], PsiClassType> capture : myCaptures) { @@ -135,7 +113,7 @@ public class InferenceIncorporationPhase { if (aType instanceof PsiWildcardType) { for (PsiType eqBound : eqBounds) { - if (mySession.isProperType(eqBound)) return false; + if (mySession.getInferenceVariable(eqBound) == null) return false; } final PsiClassType[] paramBounds = parameters[i].getExtendsListTypes(); @@ -143,15 +121,15 @@ public class InferenceIncorporationPhase { if (!((PsiWildcardType)aType).isBounded()) { for (PsiType upperBound : upperBounds) { - if (mySession.isProperType(upperBound)) { + if (mySession.getInferenceVariable(upperBound) == null) { for (PsiClassType paramBound : paramBounds) { - addConstraint(new StrictSubtypingConstraint(upperBound, paramBound)); + addConstraint(new StrictSubtypingConstraint(upperBound, mySession.substituteWithInferenceVariables(paramBound))); } } } for (PsiType lowerBound : lowerBounds) { - if (mySession.isProperType(lowerBound)) return false; + if (mySession.getInferenceVariable(lowerBound) == null) return false; } } else if (((PsiWildcardType)aType).isExtends()) { @@ -159,19 +137,19 @@ public class InferenceIncorporationPhase { final PsiType extendsBound = ((PsiWildcardType)aType).getExtendsBound(); for (PsiType upperBound : upperBounds) { - if (mySession.isProperType(upperBound)) { + if (mySession.getInferenceVariable(upperBound) == null) { if (paramBounds.length == 1 && paramBounds[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || paramBounds.length == 0) { addConstraint(new StrictSubtypingConstraint(upperBound, extendsBound)); } else if (extendsBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { for (PsiClassType paramBound : paramBounds) { - addConstraint(new StrictSubtypingConstraint(upperBound, paramBound)); + addConstraint(new StrictSubtypingConstraint(upperBound, mySession.substituteWithInferenceVariables(paramBound))); } } } } for (PsiType lowerBound : lowerBounds) { - if (mySession.isProperType(lowerBound)) return false; + if (mySession.getInferenceVariable(lowerBound) == null) return false; } } else { @@ -179,15 +157,15 @@ public class InferenceIncorporationPhase { final PsiType superBound = ((PsiWildcardType)aType).getSuperBound(); for (PsiType upperBound : upperBounds) { - if (mySession.isProperType(upperBound)) { + if (mySession.getInferenceVariable(upperBound) == null) { for (PsiClassType paramBound : paramBounds) { - addConstraint(new StrictSubtypingConstraint(paramBound, upperBound)); + addConstraint(new StrictSubtypingConstraint(mySession.substituteWithInferenceVariables(paramBound), upperBound)); } } } for (PsiType lowerBound : lowerBounds) { - if (mySession.isProperType(lowerBound)) { + if (mySession.getInferenceVariable(lowerBound) == null) { addConstraint(new StrictSubtypingConstraint(lowerBound, superBound)); } } 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); + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java index 6bc9e0b89871..8d91b620f798 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java @@ -15,9 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.graphInference; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.*; import com.intellij.psi.impl.light.LightTypeParameter; import java.util.*; @@ -139,6 +137,11 @@ public class InferenceVariable extends LightTypeParameter { } @Override + public boolean useDelegateToSubstitute() { + return false; + } + + @Override public String toString() { return getDelegate().toString(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java index b4c971b3b469..28ad946275e9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java @@ -67,12 +67,12 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper { if (typeParameters.length == 0) return PsiSubstitutor.EMPTY; InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null); for (PsiType leftType : leftTypes) { - if (!session.isProperType(leftType)) { + if (!session.isProperType(session.substituteWithInferenceVariables(leftType))) { return session.infer(); } } for (PsiType rightType : rightTypes) { - if (!session.isProperType(rightType)) { + if (!session.isProperType(session.substituteWithInferenceVariables(rightType))) { return session.infer(); } } @@ -105,10 +105,11 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper { rightTypes = new PsiType[]{param}; } final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParam}, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null); - if (inferenceSession.isProperType(param) && inferenceSession.isProperType(arg)) { + if (inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(param)) && + inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(arg))) { boolean proceed = false; for (PsiClassType classType : typeParam.getExtendsListTypes()) { - if (!inferenceSession.isProperType(classType)) { + if (!inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(classType))) { proceed = true; break; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 82b320ae99f3..b59cf70bdb69 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -19,16 +19,12 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; 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.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Iterator; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -94,7 +90,11 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (method != null && !method.isConstructor()) { returnType = method.getReturnType(); if (returnType != null) { - typeParams = method.getTypeParameters(); + List<PsiTypeParameter> params = new ArrayList<PsiTypeParameter>(); + for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(method)) { + params.add(parameter); + } + typeParams = params.toArray(new PsiTypeParameter[params.size()]); } } else if (myExpression instanceof PsiNewExpression) { //default constructor final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)myExpression).getClassOrAnonymousClassReference(); @@ -108,38 +108,8 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm } if (typeParams != null) { - - final Set<PsiTypeParameter> oldBounds = ContainerUtil.newHashSet(session.getParamsToInfer()); - final boolean sameMethodCall = session.initBounds(myExpression, typeParams); - PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; - 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]; - } - } - PsiSubstitutor siteSubstitutor = PsiSubstitutor.EMPTY; - if (method != null && !method.isConstructor()) { - if (resolveResult instanceof MethodCandidateInfo) { - siteSubstitutor = ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(); - } - else if (candidateProperties != null) { - siteSubstitutor = candidateProperties.getSubstitutor(); - } - } - 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(params, substitutor, myExpression.getManager(), myExpression); - callSession.initBounds(session.getContext(), params1.toArray(new PsiTypeParameter[params1.size()])); + final InferenceSession callSession = new InferenceSession(typeParams, PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression); + callSession.propagateVariables(session.getInferenceVariables()); if (method != null) { final PsiExpression[] args = argumentList.getExpressions(); final PsiParameter[] parameters = method.getParameterList().getParameters(); @@ -150,27 +120,12 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (!accepted) { return false; } - callSession.registerReturnTypeConstraints( - method != null && !PsiUtil.isRawSubstitutor(method, siteSubstitutor) ? siteSubstitutor.substitute(returnType) : returnType, - substitutor.substitute(returnType)); + callSession.registerReturnTypeConstraints(returnType, myT); if (callSession.repeatInferencePhases(true)) { - final Collection<InferenceVariable> inferenceVariables = callSession.getInferenceVariables(); - if (sameMethodCall) { - for (Iterator<InferenceVariable> iterator = inferenceVariables.iterator(); iterator.hasNext(); ) { - InferenceVariable variable = iterator.next(); - if (oldBounds.contains(variable.getParameter())) { - iterator.remove(); - } - } - } - session.liftBounds(myExpression, inferenceVariables); + session.registerNestedSession(callSession); } else { return false; } - final PsiType capturedReturnType = myExpression instanceof PsiMethodCallExpression - ? PsiMethodCallExpressionImpl.captureReturnType((PsiMethodCallExpression)myExpression, method, returnType, substitutor) - : substitutor.substitute(returnType); - constraints.add(new TypeCompatibilityConstraint(myT, capturedReturnType)); } } return true; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java index cbed2ea59491..c282481e79c0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java @@ -45,7 +45,7 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul constraints.add(new StrictSubtypingConstraint(myT, groundTargetType)); } else { for (PsiParameter parameter : parameters) { - if (!session.isProperType(substitutor.substitute(parameter.getType()))) { + if (!session.isProperType(session.substituteWithInferenceVariables(substitutor.substitute(parameter.getType())))) { return false; } } @@ -62,7 +62,7 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul if (returnExpressions.isEmpty() && !myExpression.isValueCompatible()) { //not value-compatible return false; } - returnType = substitutor.substitute(returnType); + returnType = session.substituteWithInferenceVariables(substitutor.substitute(returnType)); if (!session.isProperType(returnType)) { for (PsiExpression returnExpression : returnExpressions) { constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType)); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index eefd040b2a99..fbfd8195fc11 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -93,11 +93,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm if (targetParameters.length == parameters.length + 1) { specialCase(session, constraints, substitutor, targetParameters, true); for (int i = 1; i < targetParameters.length; i++) { - constraints.add(new TypeCompatibilityConstraint(psiSubstitutor.substitute(parameters[i - 1].getType()), substitutor.substitute(targetParameters[i].getType()))); + constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i - 1].getType())), + substitutor.substitute(targetParameters[i].getType()))); } } else if (targetParameters.length == parameters.length) { for (int i = 0; i < targetParameters.length; i++) { - constraints.add(new TypeCompatibilityConstraint(psiSubstitutor.substitute(parameters[i].getType()), substitutor.substitute(targetParameters[i].getType()))); + constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i].getType())), + substitutor.substitute(targetParameters[i].getType()))); } } else { return false; @@ -108,12 +110,13 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } if (applicableMethodReturnType != null) { - constraints.add(new TypeCompatibilityConstraint(returnType, psiSubstitutor.substitute(applicableMethodReturnType))); - } else if (applicableMember instanceof PsiClass || applicableMember instanceof PsiMethod && ((PsiMethod)applicableMember).isConstructor()) { + constraints.add(new TypeCompatibilityConstraint(returnType, + session.substituteWithInferenceVariables(psiSubstitutor.substitute(applicableMethodReturnType)))); + } + else if (applicableMember instanceof PsiClass || applicableMember instanceof PsiMethod && ((PsiMethod)applicableMember).isConstructor()) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(applicableMember.getProject()); - if (containingClass != null) { - final PsiClassType classType = elementFactory.createType(containingClass, psiSubstitutor); + final PsiType classType = session.substituteWithInferenceVariables(elementFactory.createType(containingClass, psiSubstitutor)); constraints.add(new TypeCompatibilityConstraint(returnType, classType)); } } @@ -122,7 +125,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.getFunctionalTypeMap(); - final PsiType added = map.put(myExpression, groundTargetType); + final PsiType added = map.put(myExpression, session.startWithFreshVars(groundTargetType)); final JavaResolveResult resolve; try { resolve = myExpression.advancedResolve(true); @@ -205,7 +208,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm PsiPolyExpressionUtil.mentionsTypeParameters(referencedMethodReturnType, ContainerUtil.newHashSet(containingClass.getTypeParameters()))) { //todo specification bug? specialCase(session, constraints, substitutor, targetParameters, false); } - constraints.add(new TypeCompatibilityConstraint(returnType, psiSubstitutor.substitute(referencedMethodReturnType))); + constraints.add(new TypeCompatibilityConstraint(returnType, session.substituteWithInferenceVariables(psiSubstitutor.substitute(referencedMethodReturnType)))); } return true; @@ -241,7 +244,8 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType); if (qualifierClass != null) { session.initBounds(qualifierClass.getTypeParameters()); - constraints.add(new StrictSubtypingConstraint(qualifierType, substitutor.substitute(targetParameters[0].getType()))); + constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType), + session.substituteWithInferenceVariables(substitutor.substitute(targetParameters[0].getType())))); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java index 29525add1549..661d59105046 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java @@ -68,7 +68,7 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR if (interfaceMethod != null) { final PsiClassType returnType = composeReturnType(containingClass, substitutor); final InferenceSession session = new InferenceSession(containingClass.getTypeParameters(), substitutor, reference.getManager(), null); - if (!(session.isProperType(returnType) && session.isProperType(interfaceMethodReturnType))) { + if (!(session.isProperType(session.substituteWithInferenceVariables(returnType)) && session.isProperType(interfaceMethodReturnType))) { session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType); substitutor = session.infer(); } @@ -116,13 +116,6 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR private PsiSubstitutor inferTypeArguments() { if (interfaceMethod == null) return substitutor; final InferenceSession session = new InferenceSession(method.getTypeParameters(), substitutor, reference.getManager(), reference); - - //lift parameters from outer call - final CurrentCandidateProperties methodSubstitutorPair = MethodCandidateInfo.getCurrentMethod(reference.getParent()); - if (methodSubstitutorPair != null) { - session.initBounds(methodSubstitutorPair.getMethod().getTypeParameters()); - } - final PsiSubstitutor psiSubstitutor = session.collectApplicabilityConstraints(reference, this, functionalInterfaceType); if (psiSubstitutor != null) { return psiSubstitutor; @@ -133,6 +126,10 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR } if (interfaceMethodReturnType != PsiType.VOID && interfaceMethodReturnType != null) { + if (method.isConstructor()) { + //todo + session.initBounds(reference, method.getContainingClass().getTypeParameters()); + } final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, substitutor) : method.getReturnType(); if (returnType != null) { session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType); |