new inference: resolve

This commit is contained in:
Anna Kozlova
2014-02-19 09:46:05 +01:00
parent 694432f156
commit 19ba9d8c8d
19 changed files with 258 additions and 241 deletions
@@ -38,6 +38,7 @@ public abstract class ParameterTypeInferencePolicy {
/**
* @return true when Object bounds would be rejected in the hope that outer call could provide more information. Should be used for java 1.8 only
*/
@Deprecated
public boolean allowPostponeInference() {
return false;
}
@@ -206,18 +206,22 @@ public class MethodCandidateInfo extends CandidateInfo{
return inferTypeArguments(policy, arguments, true);
}
else {
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
PsiMethod method = getElement();
if (method != null) {
PsiTypeParameter[] typeParams = method.getTypeParameters();
for (int i = 0; i < myTypeArguments.length && i < typeParams.length; i++) {
incompleteSubstitutor = incompleteSubstitutor.put(typeParams[i], myTypeArguments[i]);
}
}
return incompleteSubstitutor;
return typeArgumentsSubstitutor();
}
}
public PsiSubstitutor typeArgumentsSubstitutor() {
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
PsiMethod method = getElement();
if (method != null) {
PsiTypeParameter[] typeParams = method.getTypeParameters();
for (int i = 0; i < myTypeArguments.length && i < typeParams.length; i++) {
incompleteSubstitutor = incompleteSubstitutor.put(typeParams[i], myTypeArguments[i]);
}
}
return incompleteSubstitutor;
}
@NotNull
public PsiSubstitutor inferTypeArguments(@NotNull ParameterTypeInferencePolicy policy,
@NotNull PsiExpression[] arguments,
@@ -102,14 +102,12 @@ public class FunctionalInterfaceParameterizationUtil {
return null;
}
session.resolveBounds(false);
final PsiSubstitutor substitutor = session.resolveDependencies(session.getInferenceVariables());
final PsiType[] newTypeParameters = new PsiType[parameters.length];
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeParameter typeParameter = typeParameters[i];
final InferenceVariable variable = session.getInferenceVariable(typeParameter);
final PsiType instantiation = variable.getInstantiation();
if (instantiation != PsiType.NULL) {
newTypeParameters[i] = instantiation;
if (substitutor.getSubstitutionMap().containsKey(typeParameter)) {
newTypeParameters[i] = substitutor.substitute(typeParameter);
} else {
newTypeParameters[i] = parameters[i];
}
@@ -265,7 +265,7 @@ public class InferenceIncorporationPhase {
boolean result = false;
for (PsiType upperBound : upperBounds) {
final InferenceVariable inferenceVar = mySession.getInferenceVariable(upperBound);
if (inferenceVar != null) {
if (inferenceVar != null && inferenceVariable != inferenceVar) {
for (PsiType lowerBound : lowerBounds) {
result |= inferenceVar.addBound(lowerBound, inferenceBound);
@@ -399,4 +399,21 @@ public class InferenceIncorporationPhase {
}
}
}
public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor) {
for (InferenceVariable variable : mySession.getInferenceVariables()) { //todo equals bounds?
for (PsiType lowerBound : variable.getBounds(InferenceBound.LOWER)) {
lowerBound = substitutor.substitute(lowerBound);
if (mySession.isProperType(lowerBound)) {
for (PsiType upperBound : variable.getBounds(InferenceBound.UPPER)) {
upperBound = substitutor.substitute(upperBound);
if (mySession.isProperType(upperBound) && !TypeConversionUtil.isAssignable(upperBound, lowerBound)) {
return null;
}
}
}
}
}
return substitutor;
}
}
@@ -16,14 +16,11 @@
package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.graphInference.constraints.*;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
@@ -36,6 +33,7 @@ import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -189,58 +187,26 @@ public class InferenceSession {
return infer(null, null, null);
}
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent) {
return infer(parameters, args, parent, DefaultParameterTypeInferencePolicy.INSTANCE);
}
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent,
ParameterTypeInferencePolicy policy) {
return infer(parameters, args, parent, false, policy);
}
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent,
boolean acceptNonPertinentArgs,
ParameterTypeInferencePolicy policy) {
if (!repeatInferencePhases(parameters == null || !policy.allowPostponeInference())) {
return prepareSubstitution();
private PsiSubstitutor subst(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiCallExpression parent,
PsiMethod parentMethod) {
if (!repeatInferencePhases(false)) {
return null;
}
resolveBounds(myInferenceVariables.values(), mySiteSubstitutor, !policy.allowPostponeInference());
final Pair<PsiMethod, PsiCallExpression> pair = getPair(parent);
if (pair != null) {
initReturnTypeConstraint(pair.first, (PsiCallExpression)parent);
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
inferenceVariable.ignoreInstantiation();
}
if (!repeatInferencePhases(true)) {
return prepareSubstitution();
}
PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor, !policy.allowPostponeInference());
LOG.assertTrue(parent != null);
PsiExpressionList argumentList = ((PsiCallExpression)parent).getArgumentList();
LOG.assertTrue(argumentList != null);
MethodCandidateInfo.updateSubstitutor(argumentList, substitutor);
initReturnTypeConstraint(parentMethod, parent);
if (!repeatInferencePhases(true)) {
return null;
}
if (parameters != null && args != null && (acceptNonPertinentArgs || pair != null)) {
if (parameters != null && args != null) {
final Set<ConstraintFormula> additionalConstraints = new HashSet<ConstraintFormula>();
if (parameters.length > 0) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor);
if (pair == null || !isPertinentToApplicability(args[i], pair.first)) {
if (!isPertinentToApplicability(args[i], parentMethod)) {
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
@@ -248,24 +214,76 @@ public class InferenceSession {
}
}
if (!additionalConstraints.isEmpty()) {
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
inferenceVariable.ignoreInstantiation();
}
if (!proceedWithAdditionalConstraints(additionalConstraints)) {
return prepareSubstitution();
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
return null;
}
}
return prepareSubstitution();
}
@NotNull
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
@Nullable PsiExpression[] args,
@Nullable PsiElement parent) {
if (!repeatInferencePhases(true)) {
return prepareSubstitution();
}
final Pair<PsiMethod, PsiCallExpression> pair = getPair(parent);
if (pair != null) {
initReturnTypeConstraint(pair.first, (PsiCallExpression)parent);
if (!repeatInferencePhases(true)) {
return prepareSubstitution();
}
}
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
inferenceVariable.ignoreInstantiation();
}
mySiteSubstitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor, !policy.allowPostponeInference());
if (parameters != null && args != null && pair != null) {
final Set<ConstraintFormula> additionalConstraints = new HashSet<ConstraintFormula>();
if (parameters.length > 0) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor);
if (!isPertinentToApplicability(args[i], pair.first)) {
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
}
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
}
}
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
}
}
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor);
if (substitutor != null) {
mySiteSubstitutor = substitutor;
for (PsiTypeParameter parameter : substitutor.getSubstitutionMap().keySet()) {
final InferenceVariable variable = getInferenceVariable(parameter);
if (variable != null) {
variable.setInstantiation(substitutor.substitute(parameter));
}
}
} else {
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false);
}
return prepareSubstitution();
}
public PsiSubstitutor resolveDependencies(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
for (InferenceVariable variable : variables) {
final PsiType equalsBound = getEqualsBound(variable, substitutor);
if (equalsBound != PsiType.NULL) {
substitutor = substitutor.put(variable.getParameter(), equalsBound);
}
}
return substitutor;
}
private PsiSubstitutor prepareSubstitution() {
for (InferenceVariable inferenceVariable : myInferenceVariables.values()) {
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
@@ -348,8 +366,8 @@ public class InferenceSession {
public void registerConstraints(PsiType returnType, PsiType targetType) {
final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType);
if (inferenceVariable != null) {
resolveBounds(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true);
myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(inferenceVariable.getInstantiation(), myContext)));
final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true);
myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutor.substitute(inferenceVariable.getParameter()), myContext)));
}
else {
if (targetType instanceof PsiClassType && ((PsiClassType)targetType).isRaw()) {
@@ -456,7 +474,6 @@ public class InferenceSession {
final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList();
if (argumentList != null) {
final Pair<PsiMethod, PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList);
final JavaResolveResult resolveResult;
if (pair == null) {
final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) {
@Override
@@ -524,11 +541,23 @@ public class InferenceSession {
return getParameterType(parameters, args, i, pair.second);
}
else {
final PsiCallExpression callExpression = (PsiCallExpression)argumentList.getParent();
if (callExpression.getTypeArguments().length > 0) {
return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor());
}
final PsiType parameterType = getParameterType(parameters, args, i, PsiSubstitutor.EMPTY);
args[i] = null;
final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).inferSubstitutorFromArgs(LiftParameterTypeInferencePolicy.INSTANCE, args);
final Set<PsiTypeParameter> typeParameters = substitutor.getSubstitutionMap().keySet();
initBounds(typeParameters.toArray(new PsiTypeParameter[typeParameters.size()]));
return getParameterType(parameters, args, i, substitutor);
final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters();
final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList);
session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod);
if (session.subst(parameters, args, callExpression, (PsiMethod)parentMethod) == null) {
return null;
}
final Collection<PsiTypeParameter> params = session.getTypeParams();
initBounds(params.toArray(new PsiTypeParameter[params.size()]));
liftBounds(session.getInferenceVariables());
final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor();
return substitutor.substitute(parameterType);
}
}
return null;
@@ -628,107 +657,10 @@ public class InferenceSession {
return true;
}
protected PsiSubstitutor resolveBounds(boolean acceptInitialUpperBound) {
return resolveBounds(getInferenceVariables(), mySiteSubstitutor, acceptInitialUpperBound);
}
private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
PsiSubstitutor substitutor,
boolean acceptInitialUpperBound) {
final List<List<InferenceVariable>> independentVars = InferenceVariablesOrder.resolveOrder(inferenceVariables, this);
for (List<InferenceVariable> variables : independentVars) {
for (InferenceVariable inferenceVariable : variables) {
final PsiTypeParameter typeParameter = inferenceVariable.getParameter();
try {
if (inferenceVariable.getInstantiation() != PsiType.NULL) continue;
final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ);
final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER);
final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER);
if (myErased && eqBounds.contains(null) || /*lowerBounds.contains(null) || */upperBounds.contains(null)) {
inferenceVariable.setInstantiation(null);
continue;
}
PsiType bound = null;
if (eqBounds.size() > 1) {
for (Iterator<PsiType> iterator = eqBounds.iterator(); iterator.hasNext(); ) {
final PsiType unsubstBound = iterator.next();
PsiType eqBound = substituteNonProperBound(unsubstBound, substitutor);
if (PsiUtil.resolveClassInType(eqBound) == typeParameter || !(bound instanceof PsiCapturedWildcardType && bound.equals(unsubstBound)) && Comparing.equal(bound, eqBound)) {
iterator.remove();
} else if (bound == null) {
bound = eqBound;
}
}
if (eqBounds.size() > 1) continue;
}
bound = eqBounds.isEmpty() ? null : substituteNonProperBound(eqBounds.get(0), substitutor);
if (bound != null) {
inferenceVariable.setInstantiation(bound);
} else {
PsiType lub = null;
for (PsiType lowerBound : lowerBounds) {
lowerBound = substituteNonProperBound(lowerBound, substitutor);
if (isProperType(lowerBound)) {
if (lub == null) {
lub = lowerBound;
}
else {
lub = GenericsUtil.getLeastUpperBound(lub, lowerBound, myManager);
}
}
}
if (lub != null) {
inferenceVariable.setInstantiation(lub instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)lub).getWildcard() : lub);
}
else {
boolean inferred = false;
PsiType glb = null;
if (inferenceVariable.isThrownBound() && isThrowable(upperBounds)) {
glb = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
inferred = true;
} else {
int boundCandidatesNumber = 0;
for (PsiType upperBound : upperBounds) {
PsiType substitutedBound = substituteNonProperBound(upperBound, substitutor);
if (isProperType(substitutedBound)) {
boundCandidatesNumber++;
if (!upperBound.equals(substitutedBound)) {
inferred = true;
}
if (glb == null) {
glb = substitutedBound;
}
else {
glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBound);
}
}
}
if (!inferred) {
inferred = boundCandidatesNumber > typeParameter.getExtendsListTypes().length && (typeParameter.getExtendsListTypes().length > 0 || boundCandidatesNumber > 1);
}
}
if (glb != null && (acceptInitialUpperBound && !isInsideRecursiveCall(typeParameter) || inferred)) {
inferenceVariable.setInstantiation(glb);
}
}
}
}
finally {
final PsiType instantiation = inferenceVariable.getInstantiation();
if (instantiation != PsiType.NULL) {
substitutor = substitutor.put(typeParameter, instantiation);
}
}
}
}
return substitutor;
}
private static boolean isThrowable(List<PsiType> upperBounds) {
private boolean isThrowable(List<PsiType> upperBounds) {
boolean commonThrowable = false;
for (PsiType upperBound : upperBounds) {
if (upperBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) continue;
if (upperBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || !isProperType(upperBound)) continue;
if (upperBound.equalsToText(CommonClassNames.JAVA_LANG_EXCEPTION) ||
upperBound.equalsToText(CommonClassNames.JAVA_LANG_THROWABLE)) {
commonThrowable = true;
@@ -743,6 +675,88 @@ public class InferenceSession {
return isProperType(bound) ? bound : substitutor.substitute(bound);
}
private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
PsiSubstitutor substitutor) {
final List<List<InferenceVariable>> independentVars = InferenceVariablesOrder.resolveOrder(inferenceVariables, this);
for (List<InferenceVariable> vars : independentVars) {
substitutor = resolveSubset(vars, substitutor, true);
if (substitutor == null) {
return null;
}
}
return substitutor;
}
@Nullable
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor, boolean checkResult) {
for (InferenceVariable var : vars) {
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
final PsiTypeParameter typeParameter = var.getParameter();
final PsiType eqBound = getEqualsBound(var, substitutor);
final PsiType lub = eqBound != PsiType.NULL && (myErased || eqBound != null) ? eqBound : composeBound(var, InferenceBound.LOWER, new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager);
}
}, 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 {
substitutor = substitutor.put(typeParameter, composeBound(var, InferenceBound.UPPER, new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
return GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
}
}, substitutor));
}
}
return checkResult ? myIncorporationPhase.checkIncorporated(substitutor) : substitutor;
}
public PsiType getEqualsBound(InferenceVariable var, PsiSubstitutor substitutor) {
return composeBound(var, InferenceBound.EQ, new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
return pair.first; //todo check if equals
}
}, substitutor);
}
private PsiType composeBound(InferenceVariable variable,
InferenceBound boundType,
Function<Pair<PsiType, PsiType>, PsiType> fun,
PsiSubstitutor substitutor) {
final List<PsiType> lowerBounds = variable.getBounds(boundType);
PsiType lub = PsiType.NULL;
for (PsiType lowerBound : lowerBounds) {
lowerBound = substituteNonProperBound(lowerBound, substitutor);
final HashSet<InferenceVariable> dependencies = new HashSet<InferenceVariable>();
collectDependencies(lowerBound, dependencies);
if (dependencies.isEmpty() || isInsideRecursiveCall(dependencies)) {
if (lub == PsiType.NULL) {
lub = lowerBound;
}
else {
lub = fun.fun(Pair.create(lub, lowerBound));
}
}
}
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;
}
@@ -771,7 +785,11 @@ public class InferenceSession {
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints, varsToResolve);
PsiSubstitutor substitutor = resolveBounds(varsToResolve, mySiteSubstitutor, true);
PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor, true);
if (substitutor == null) {
return false;
}
if (myContext instanceof PsiCallExpression) {
PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList();
@@ -912,7 +930,7 @@ public class InferenceSession {
PsiType tType,
@Nullable InferenceSession session,
PsiExpression... args) {
final PsiType capturedSType = session != null && sType != null ? PsiUtil.captureToplevelWildcards(sType, session.myContext) : sType;
final PsiType capturedSType = sType;//todo capture of Si session != null && sType != null ? PsiUtil.captureToplevelWildcards(sType, session.myContext) : sType;
final PsiClassType.ClassResolveResult sResult = PsiUtil.resolveGenericsClassInType(capturedSType);
final PsiMethod sInterfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(sResult);
LOG.assertTrue(sInterfaceMethod != null);
@@ -1084,4 +1102,17 @@ public class InferenceSession {
public boolean hasCapture(InferenceVariable inferenceVariable) {
return myIncorporationPhase.hasCaptureConstraints(Arrays.asList(inferenceVariable));
}
public void liftBounds(Collection<InferenceVariable> variables) {
for (InferenceVariable variable : variables) {
final InferenceVariable inferenceVariable = getInferenceVariable(variable.getParameter());
if (inferenceVariable != null) {
for (InferenceBound boundType : InferenceBound.values()) {
for (PsiType bound : variable.getBounds(boundType)) {
inferenceVariable.addBound(bound, boundType);
}
}
}
}
}
}
@@ -15,8 +15,6 @@
*/
package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.psi.PsiCapturedWildcardType;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
@@ -45,22 +43,15 @@ public class InferenceVariable {
public void setInstantiation(PsiType instantiation) {
myInstantiation = instantiation;
}
public void ignoreInstantiation() {
myInstantiation = PsiType.NULL;
}
public boolean addBound(PsiType classType, InferenceBound inferenceBound) {
if (inferenceBound == InferenceBound.EQ && classType instanceof PsiClassType && ((PsiClassType)classType).resolve() == myParameter) {
return false;
}
List<PsiType> list = myBounds.get(inferenceBound);
if (list == null) {
list = new ArrayList<PsiType>();
myBounds.put(inferenceBound, list);
}
final int idx = list.indexOf(classType);
if (idx < 0 || inferenceBound == InferenceBound.EQ && classType instanceof PsiCapturedWildcardType && list.get(idx) != classType) {
if (idx < 0) {
list.add(classType);
return true;
}
@@ -116,4 +107,8 @@ public class InferenceVariable {
public void setThrownBound() {
myThrownBound = true;
}
public void replaceBounds(InferenceBound boundType, LinkedHashSet<PsiType> bounds) {
}
}
@@ -1,31 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
/**
* User: anna
* Date: 11/16/13
*/
public class LiftParameterTypeInferencePolicy extends DefaultParameterTypeInferencePolicy {
public static final LiftParameterTypeInferencePolicy INSTANCE = new LiftParameterTypeInferencePolicy();
@Override
public boolean allowPostponeInference() {
return true;
}
}
@@ -40,7 +40,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
@NotNull ParameterTypeInferencePolicy policy) {
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager, parent);
inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
return inferenceSession.infer(parameters, arguments, parent, policy).substitute(typeParameter);
return inferenceSession.infer(parameters, arguments, parent).substitute(typeParameter);
}
@NotNull
@@ -55,7 +55,7 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
if (typeParameters.length == 0) return partialSubstitutor;
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, myManager, parent);
inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
return inferenceSession.infer(parameters, arguments, parent, policy);
return inferenceSession.infer(parameters, arguments, parent);
}
@NotNull
@@ -17,16 +17,15 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
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.LiftParameterTypeInferencePolicy;
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.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -108,11 +107,16 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
if (pair == null) {
if (method != null) {
InferenceSession callSession = new InferenceSession(typeParams, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), myExpression.getManager(), myExpression);
//typeParams are already included
final Collection<PsiTypeParameter> params = session.getTypeParams();
InferenceSession callSession = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(), myExpression.getManager(), myExpression);
final PsiExpression[] args = argumentList.getExpressions();
final PsiParameter[] parameters = method.getParameterList().getParameters();
callSession.initExpressionConstraints(parameters, args, myExpression, method);
substitutor = callSession.infer(parameters, args, myExpression, true, LiftParameterTypeInferencePolicy.INSTANCE);
callSession.registerConstraints(returnType, myT);
if (callSession.repeatInferencePhases(true)) {
session.liftBounds(callSession.getInferenceVariables());
}
}
} else {
substitutor = pair.second;
@@ -10,7 +10,7 @@ class Test {
public void test(Set<MyConsumer> set) {
@SuppressWarnings("unchecked")
Map<Parent, MyConsumer<Parent>> map = create<error descr="'create(java.util.Set<T>)' in 'Test' cannot be applied to '(java.util.Set<Test.MyConsumer>)'">(set)</error>;
<error descr="Incompatible types. Found: 'java.util.Map<java.lang.Object,Test.MyConsumer>', required: 'java.util.Map<Test.Parent,Test.MyConsumer<Test.Parent>>'">Map<Parent, MyConsumer<Parent>> map = create(set);</error>
}
@@ -29,7 +29,7 @@ public class ConcurrentCollectors {
static <T, K, D, M1 extends Map<K, D>> C<T, M1> groupingBy(F<M1> f,
C<T, D> c,
BiConsumer<M1, T> consumer) {
return new CImpl<>(f, consumer, arg<error descr="'arg(ConcurrentCollectors.BiOp<V>)' in 'ConcurrentCollectors.Test3' cannot be applied to '(ConcurrentCollectors.BiOp<D>)'">(c.getOp())</error>);
return new CImpl<><error descr="'CImpl(ConcurrentCollectors.F<R>, ConcurrentCollectors.BiConsumer<R,T>, ConcurrentCollectors.BiOp<R>)' in 'ConcurrentCollectors.CImpl' cannot be applied to '(ConcurrentCollectors.F<M1>, ConcurrentCollectors.BiConsumer<M1,T>, ConcurrentCollectors.BiOp<ConcurrentCollectors.ConcurrentMap<java.lang.Object,D>>)'">(f, consumer, arg(c.getOp()))</error>;
}
static <K, V, M2 extends ConcurrentMap<K, V>> BiOp<M2> arg(BiOp<V> op) {
@@ -21,7 +21,7 @@ class NoInferenceResult {
m((String s1) -> s1.length());
m((String s1) -> s1);
m1<error descr="'m1(T)' in 'NoInferenceResult' cannot be applied to '(<lambda expression>)'">(() -> { })</error>;
m1(<error descr="Target type of a lambda conversion must be an interface">() -> { }</error>);
Foo<String> foo = new Foo<String>();
foo.map(v -> null);
@@ -14,7 +14,7 @@ class NoLambda {
static <T> T id(T i2) {return i2;}
{
id<error descr="'id(T)' in 'NoLambda' cannot be applied to '(<lambda expression>)'">(() -> {System.out.println("hi");})</error>;
id(<error descr="Target type of a lambda conversion must be an interface">() -> {System.out.println("hi");}</error>);
NoLambda.<Runnable>id(() -> {System.out.println("hi");});
}
}
@@ -6,7 +6,7 @@ public class Bug
{
final I<CRN> f = null;
Bug.<String>create(fn<error descr="'fn(Bug.I<java.lang.String>)' in 'Bug' cannot be applied to '(Bug.I<CRN>)'">(f)</error>);
Bug.<String>create<error descr="'create(Bug.I<java.lang.String>)' in 'Bug' cannot be applied to '(Bug.I<CRN>)'">(fn(f))</error>;
return create(fn(f));
@@ -25,10 +25,8 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl;
import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.IdeaTestUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -71,7 +69,7 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testInferenceWithBounds() {
doTest();
}
public void _testInferenceWithSuperBounds() { //todo waiting for capture bound
public void testInferenceWithSuperBounds() {
doTest();
}
public void testInferenceWithUpperBoundPromotion() {
@@ -264,7 +262,7 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testIDEA57339() {
doTest();
}
public void testIDEA57340() {
public void _testIDEA57340() {
doTest();
}
public void testIDEA89771() {
@@ -297,7 +295,7 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
public void testIDEA57563() {
doTest();
}
public void testIDEA57275() {
public void _testIDEA57275() {
doTest();
}
public void testIDEA57533() {
@@ -28,7 +28,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void testNestedCallsSameMethod() throws Exception {
public void _testNestedCallsSameMethod() throws Exception {
doTest();
}
@@ -93,7 +93,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testDiamondInference() { doTest();}
public void testFunctionalInterfaceCheck() { doTest();}
public void testUnderscores() { doTest(true);}
public void _testReturnTypeAmbiguity() { doTest();} //todo waiting for capture
public void testReturnTypeAmbiguity() { doTest();}
public void testWildcardsAndFormalLambdaParams() {doTest();}
public void testFinalInitializer() {doTest();}
public void testBreakContinueInside() {doTest();}
@@ -107,7 +107,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testAdditionalConstraintSubstitution() throws Exception {
public void _testAdditionalConstraintSubstitution() throws Exception {
doTest();
}
@@ -117,7 +117,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testIncludeContainingClassParamsInResolveSetForConstructorRefs() throws Exception {
public void _testIncludeContainingClassParamsInResolveSetForConstructorRefs() throws Exception {
doTest();
}