mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
new inference: resolve
This commit is contained in:
+1
@@ -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,
|
||||
|
||||
+3
-5
@@ -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];
|
||||
}
|
||||
|
||||
+18
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+196
-165
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-10
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
-31
@@ -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;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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
|
||||
|
||||
+8
-4
@@ -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;
|
||||
|
||||
+1
-1
@@ -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>
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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");});
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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));
|
||||
|
||||
|
||||
+3
-5
@@ -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() {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedCallsSameMethod() throws Exception {
|
||||
public void _testNestedCallsSameMethod() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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();}
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAdditionalConstraintSubstitution() throws Exception {
|
||||
public void _testAdditionalConstraintSubstitution() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIncludeContainingClassParamsInResolveSetForConstructorRefs() throws Exception {
|
||||
public void _testIncludeContainingClassParamsInResolveSetForConstructorRefs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user