mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
new inference: start inference from top to bottom; ensure getTargetType doesn't perform any inference; cache intermediate results
This commit is contained in:
@@ -363,6 +363,10 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
return myInferenceError;
|
||||
}
|
||||
|
||||
public CurrentCandidateProperties createProperties() {
|
||||
return new CurrentCandidateProperties(this, getSiteSubstitutor(), isVarargs(), false);
|
||||
}
|
||||
|
||||
public static class CurrentCandidateProperties {
|
||||
private final MethodCandidateInfo myMethod;
|
||||
private PsiSubstitutor mySubstitutor;
|
||||
|
||||
+4
@@ -339,4 +339,8 @@ public class InferenceIncorporationPhase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Pair<PsiTypeParameter[], PsiClassType>> getCaptures() {
|
||||
return myCaptures;
|
||||
}
|
||||
}
|
||||
|
||||
+130
-88
@@ -18,7 +18,6 @@ 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.Comparing;
|
||||
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;
|
||||
@@ -65,7 +64,7 @@ public class InferenceSession {
|
||||
private final Set<InferenceVariable> myInferenceVariables = new LinkedHashSet<InferenceVariable>();
|
||||
private final List<ConstraintFormula> myConstraints = new ArrayList<ConstraintFormula>();
|
||||
private final Set<ConstraintFormula> myConstraintsCopy = new HashSet<ConstraintFormula>();
|
||||
private final InferenceSessionContainer myInferenceSessionContainer = new InferenceSessionContainer();
|
||||
private InferenceSessionContainer myInferenceSessionContainer = new InferenceSessionContainer();
|
||||
|
||||
private PsiSubstitutor mySiteSubstitutor;
|
||||
private final PsiManager myManager;
|
||||
@@ -81,8 +80,22 @@ public class InferenceSession {
|
||||
|
||||
private PsiSubstitutor myInferenceSubstitution = PsiSubstitutor.EMPTY;
|
||||
|
||||
public InferenceSession(InitialInferenceState initialState) {
|
||||
myContext = initialState.getContext();
|
||||
myManager = myContext.getManager();
|
||||
|
||||
myInferenceSubstitution = initialState.getInferenceSubstitutor();
|
||||
myInferenceVariables.addAll(initialState.getInferenceVariables());
|
||||
mySiteSubstitutor = initialState.getSiteSubstitutor();
|
||||
|
||||
for (Pair<PsiTypeParameter[], PsiClassType> capture : initialState.getCaptures()) {
|
||||
myIncorporationPhase.addCapture(capture.first, capture.second);
|
||||
}
|
||||
myInferenceSessionContainer = initialState.getInferenceSessionContainer();
|
||||
}
|
||||
|
||||
public InferenceSession(PsiTypeParameter[] typeParams,
|
||||
PsiType[] leftTypes,
|
||||
PsiType[] leftTypes,
|
||||
PsiType[] rightTypes,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
PsiManager manager,
|
||||
@@ -278,23 +291,49 @@ public class InferenceSession {
|
||||
return infer(null, null, null);
|
||||
}
|
||||
|
||||
|
||||
public PsiSubstitutor collectAdditionalAndInfer(@NotNull PsiParameter[] parameters,
|
||||
@NotNull PsiExpression[] args,
|
||||
@NotNull MethodCandidateInfo.CurrentCandidateProperties properties,
|
||||
@NotNull PsiSubstitutor psiSubstitutor) {
|
||||
return doInfer(parameters, args, myContext, properties, psiSubstitutor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
|
||||
return infer(parameters, args, parent, getCurrentProperties(parent));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent,
|
||||
@Nullable MethodCandidateInfo.CurrentCandidateProperties properties) {
|
||||
return doInfer(parameters, args, parent, properties, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiSubstitutor doInfer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent,
|
||||
@Nullable MethodCandidateInfo.CurrentCandidateProperties properties,
|
||||
PsiSubstitutor initialSubstitutor) {
|
||||
try {
|
||||
if (!repeatInferencePhases(true)) {
|
||||
if (initialSubstitutor == null && !repeatInferencePhases(true)) {
|
||||
//inferred result would be checked as candidate won't be applicable
|
||||
return resolveSubset(myInferenceVariables, mySiteSubstitutor);
|
||||
}
|
||||
|
||||
if (properties != null && !properties.isApplicabilityCheck()) {
|
||||
initReturnTypeConstraint(properties.getMethod(), (PsiCall)parent);
|
||||
if (!repeatInferencePhases(true)) {
|
||||
return prepareSubstitution();
|
||||
if (initialSubstitutor == null) {
|
||||
initReturnTypeConstraint(properties.getMethod(), (PsiCall)parent);
|
||||
if (!repeatInferencePhases(true)) {
|
||||
return prepareSubstitution();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (parameters != null && args != null) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
|
||||
if (parameters.length > 0) {
|
||||
@@ -307,7 +346,11 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, PsiSubstitutor.EMPTY);
|
||||
if (initialSubstitutor == null) {
|
||||
initialSubstitutor = PsiSubstitutor.EMPTY;
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables, initialSubstitutor);
|
||||
if (substitutor != null) {
|
||||
if (myContext != null) {
|
||||
myContext.putUserData(ERASED, myErased);
|
||||
@@ -373,16 +416,16 @@ public class InferenceSession {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCall)arg);
|
||||
}
|
||||
}
|
||||
else if (arg instanceof PsiLambdaExpression &&
|
||||
isPertinentToApplicability(arg, parentMethod) &&
|
||||
!isProperType(retrieveNonPrimitiveEqualsBounds(myInferenceVariables).substitute(parameterType))) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType);
|
||||
else if (arg instanceof PsiLambdaExpression &&
|
||||
isPertinentToApplicability(arg, parentMethod)) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType,
|
||||
!isProperType(retrieveNonPrimitiveEqualsBounds(myInferenceVariables).substitute(parameterType)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiMethod getCalledMethod(PsiCall arg) {
|
||||
public static PsiMethod getCalledMethod(PsiCall arg) {
|
||||
final PsiExpressionList argumentList = arg.getArgumentList();
|
||||
if (argumentList == null) {
|
||||
return null;
|
||||
@@ -392,7 +435,7 @@ public class InferenceSession {
|
||||
if (properties != null) {
|
||||
return properties.getMethod();
|
||||
}
|
||||
final JavaResolveResult resolveResult = getMethodResult(arg);
|
||||
final JavaResolveResult resolveResult = getResolveResult(arg);
|
||||
if (resolveResult instanceof MethodCandidateInfo) {
|
||||
return (PsiMethod)resolveResult.getElement();
|
||||
}
|
||||
@@ -403,34 +446,41 @@ public class InferenceSession {
|
||||
|
||||
private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
PsiLambdaExpression lambdaExpression,
|
||||
PsiType parameterType) {
|
||||
PsiType parameterType,
|
||||
boolean addConstraint) {
|
||||
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
|
||||
if (interfaceReturnType != null) {
|
||||
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
|
||||
for (PsiExpression returnExpression : returnExpressions) {
|
||||
processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType);
|
||||
processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType, addConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processReturnExpression(Set<ConstraintFormula> additionalConstraints,
|
||||
PsiExpression returnExpression,
|
||||
PsiType functionalType) {
|
||||
PsiType functionalType,
|
||||
boolean addConstraint) {
|
||||
if (returnExpression instanceof PsiCallExpression) {
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression);
|
||||
if (addConstraint) {
|
||||
final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
|
||||
if (calledMethod != null && PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
|
||||
collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression);
|
||||
}
|
||||
}
|
||||
else {
|
||||
getInferenceSessionContainer().registerNestedSession(this, functionalType, returnExpression);
|
||||
}
|
||||
}
|
||||
else if (returnExpression instanceof PsiParenthesizedExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType);
|
||||
processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType, addConstraint);
|
||||
}
|
||||
else if (returnExpression instanceof PsiConditionalExpression) {
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType);
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType);
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType, addConstraint);
|
||||
processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType, addConstraint);
|
||||
}
|
||||
else if (returnExpression instanceof PsiLambdaExpression) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType);
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType, myErased);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,9 +488,9 @@ public class InferenceSession {
|
||||
final PsiCall callExpression) {
|
||||
PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final JavaResolveResult result = getMethodResult(callExpression);
|
||||
MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null;
|
||||
final JavaResolveResult result = properties != null ? null : getResolveResult(callExpression);
|
||||
final PsiMethod method = properties != null ? properties.getMethod() : result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : null;
|
||||
if (method != null) {
|
||||
final PsiExpression[] newArgs = argumentList.getExpressions();
|
||||
final PsiParameter[] newParams = method.getParameterList().getParameters();
|
||||
@@ -451,23 +501,6 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
private static JavaResolveResult getMethodResult(final PsiCall callExpression) {
|
||||
final PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
|
||||
final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class);
|
||||
final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() {
|
||||
@Override
|
||||
public JavaResolveResult compute() {
|
||||
return getResolveResult(callExpression);
|
||||
}
|
||||
};
|
||||
MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
return properties != null ? null :
|
||||
expression == null || !PsiResolveHelper.ourGraphGuard.currentStack().contains(expression)
|
||||
? computableResolve.compute()
|
||||
: PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
|
||||
}
|
||||
|
||||
public static JavaResolveResult getResolveResult(final PsiCall callExpression) {
|
||||
if (callExpression instanceof PsiNewExpression) {
|
||||
PsiUtilCore.ensureValid(callExpression);
|
||||
@@ -543,6 +576,15 @@ public class InferenceSession {
|
||||
return mySiteSubstitutor;
|
||||
}
|
||||
|
||||
public InitialInferenceState createInitialState() {
|
||||
return new InitialInferenceState(myInferenceVariables,
|
||||
myContext,
|
||||
myInferenceSubstitution,
|
||||
mySiteSubstitutor,
|
||||
myIncorporationPhase.getCaptures(),
|
||||
myInferenceSessionContainer);
|
||||
}
|
||||
|
||||
public void initBounds(PsiTypeParameter... typeParameters) {
|
||||
initBounds(myContext, typeParameters);
|
||||
}
|
||||
@@ -580,7 +622,7 @@ public class InferenceSession {
|
||||
PsiPolyExpressionUtil.isMethodCallPolyExpression((PsiExpression)context, method)) {
|
||||
PsiType returnType = method.getReturnType();
|
||||
if (!PsiType.VOID.equals(returnType) && returnType != null) {
|
||||
PsiType targetType = getTargetType(context);
|
||||
PsiType targetType = getTargetTypeFromParent(context, false);
|
||||
if (targetType != null && !PsiType.VOID.equals(targetType)) {
|
||||
registerReturnTypeConstraints(
|
||||
PsiUtil.isRawSubstitutor(method, mySiteSubstitutor) ? returnType : mySiteSubstitutor.substitute(returnType), targetType);
|
||||
@@ -691,6 +733,15 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
public static PsiType getTargetType(final PsiElement context) {
|
||||
return getTargetTypeFromParent(context, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inferParent false during inference;
|
||||
* conditional expression type can't be asked during inference as it is a poly expression and
|
||||
* {@link ExpressionCompatibilityConstraint} should be created instead
|
||||
*/
|
||||
private static PsiType getTargetTypeFromParent(final PsiElement context, boolean inferParent) {
|
||||
PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context);
|
||||
if (targetType != null) {
|
||||
return targetType;
|
||||
@@ -708,42 +759,35 @@ public class InferenceSession {
|
||||
if (properties != null && properties.isApplicabilityCheck()) {
|
||||
return getTypeByMethod(context, argumentList, properties.getMethod(), properties.isVarargs(), properties.getSubstitutor());
|
||||
}
|
||||
final JavaResolveResult result = properties != null ? properties.getInfo() : ((PsiCall)gParent).resolveMethodGenerics();
|
||||
final boolean varargs = chooseVarargsMode(properties, result);
|
||||
PsiSubstitutor substitutor = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, false,
|
||||
new Computable<PsiSubstitutor>() {
|
||||
@Override
|
||||
public PsiSubstitutor compute() {
|
||||
return result.getSubstitutor();
|
||||
}
|
||||
}
|
||||
);
|
||||
if (substitutor == null && properties != null) {
|
||||
substitutor = properties.getSubstitutor();
|
||||
|
||||
if (inferParent) {
|
||||
final JavaResolveResult result = ((PsiCall)gParent).resolveMethodGenerics();
|
||||
final boolean varargs = result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isVarargs();
|
||||
return getTypeByMethod(context, argumentList, result.getElement(), varargs, result.getSubstitutor());
|
||||
}
|
||||
return getTypeByMethod(context, argumentList, result.getElement(), varargs, substitutor);
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof PsiConditionalExpression) {
|
||||
return getTargetType(parent);
|
||||
}
|
||||
else if (parent instanceof PsiConditionalExpression) {
|
||||
return getTargetTypeFromParent(parent, inferParent);
|
||||
}
|
||||
else if (parent instanceof PsiLambdaExpression) {
|
||||
return getTargetTypeByContainingLambda((PsiLambdaExpression)parent);
|
||||
return getTargetTypeFromParentLambda((PsiLambdaExpression)parent, inferParent);
|
||||
}
|
||||
else if (parent instanceof PsiReturnStatement) {
|
||||
return getTargetTypeByContainingLambda(PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class));
|
||||
return getTargetTypeFromParentLambda(PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, true, PsiMethod.class), inferParent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiType getTargetTypeByContainingLambda(PsiLambdaExpression lambdaExpression) {
|
||||
private static PsiType getTargetTypeFromParentLambda(PsiLambdaExpression lambdaExpression, boolean inferParent) {
|
||||
if (lambdaExpression != null) {
|
||||
if (PsiUtil.skipParenthesizedExprUp(lambdaExpression.getParent()) instanceof PsiExpressionList) {
|
||||
final PsiType typeTypeByParentCall = getTargetType(lambdaExpression);
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(
|
||||
FunctionalInterfaceParameterizationUtil.getGroundTargetType(typeTypeByParentCall, lambdaExpression));
|
||||
final PsiType typeTypeByParentCall = getTargetTypeFromParent(lambdaExpression, inferParent);
|
||||
if (typeTypeByParentCall != null) {
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(FunctionalInterfaceParameterizationUtil.getGroundTargetType(typeTypeByParentCall, lambdaExpression));
|
||||
}
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression.getFunctionalInterfaceType());
|
||||
return inferParent || !(PsiUtil.skipParenthesizedExprUp(lambdaExpression.getParent()) instanceof PsiExpressionList)
|
||||
? LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression.getFunctionalInterfaceType()) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -995,8 +1039,8 @@ public class InferenceSession {
|
||||
@NotNull
|
||||
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) {
|
||||
for (InferenceVariable var : vars) {
|
||||
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
|
||||
final PsiType type = checkBoundsConsistency(substitutor, var);
|
||||
final PsiType instantiation = var.getInstantiation();
|
||||
final PsiType type = instantiation == PsiType.NULL ? checkBoundsConsistency(substitutor, var) : instantiation;
|
||||
if (type != PsiType.NULL) {
|
||||
substitutor = substitutor.put(var, type);
|
||||
}
|
||||
@@ -1013,10 +1057,9 @@ public class InferenceSession {
|
||||
PsiType type;
|
||||
if (eqBound != PsiType.NULL && (myErased || eqBound != null)) {
|
||||
if (lowerBound != PsiType.NULL && !TypeConversionUtil.isAssignable(eqBound, lowerBound)) {
|
||||
registerIncompatibleErrorMessage(
|
||||
incompatibleBoundsMessage(var, substitutor, InferenceBound.EQ, EQUALITY_CONSTRAINTS_PRESENTATION, InferenceBound.LOWER, LOWER_BOUNDS_PRESENTATION)
|
||||
);
|
||||
return PsiType.NULL;
|
||||
final String incompatibleBoundsMessage =
|
||||
incompatibleBoundsMessage(var, substitutor, InferenceBound.EQ, EQUALITY_CONSTRAINTS_PRESENTATION, InferenceBound.LOWER, LOWER_BOUNDS_PRESENTATION);
|
||||
return registerIncompatibleErrorMessage(var, incompatibleBoundsMessage);
|
||||
} else {
|
||||
type = eqBound;
|
||||
}
|
||||
@@ -1036,8 +1079,7 @@ public class InferenceSession {
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
final String conflictingConjunctsMessage = ((PsiIntersectionType)type).getConflictingConjunctsMessage();
|
||||
if (conflictingConjunctsMessage != null) {
|
||||
registerIncompatibleErrorMessage("Type parameter " + var.getName() + " has incompatible upper bounds: " + conflictingConjunctsMessage);
|
||||
return PsiType.NULL;
|
||||
return registerIncompatibleErrorMessage(var, "Type parameter " + var.getName() + " has incompatible upper bounds: " + conflictingConjunctsMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1052,8 +1094,7 @@ public class InferenceSession {
|
||||
incompatibleBoundsMessage = incompatibleBoundsMessage(var, substitutor, InferenceBound.LOWER, LOWER_BOUNDS_PRESENTATION, InferenceBound.UPPER, UPPER_BOUNDS_PRESENTATION);
|
||||
}
|
||||
if (incompatibleBoundsMessage != null) {
|
||||
registerIncompatibleErrorMessage(incompatibleBoundsMessage);
|
||||
return PsiType.NULL;
|
||||
return registerIncompatibleErrorMessage(var, incompatibleBoundsMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1061,13 +1102,16 @@ public class InferenceSession {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void registerIncompatibleErrorMessage(String value) {
|
||||
if (myErrorMessages == null) {
|
||||
myErrorMessages = new ArrayList<String>();
|
||||
}
|
||||
if (!myErrorMessages.contains(value)) {
|
||||
myErrorMessages.add(value);
|
||||
private PsiType registerIncompatibleErrorMessage(InferenceVariable var, @NotNull String incompatibleBoundsMessage) {
|
||||
if (var.getCallContext() == myContext) {
|
||||
if (myErrorMessages == null) {
|
||||
myErrorMessages = new ArrayList<String>();
|
||||
}
|
||||
if (!myErrorMessages.contains(incompatibleBoundsMessage)) {
|
||||
myErrorMessages.add(incompatibleBoundsMessage);
|
||||
}
|
||||
}
|
||||
return PsiType.NULL;
|
||||
}
|
||||
|
||||
private String incompatibleBoundsMessage(final InferenceVariable var,
|
||||
@@ -1234,9 +1278,7 @@ public class InferenceSession {
|
||||
PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
PsiType parameterType = ((ExpressionCompatibilityConstraint)formula).getT();
|
||||
if (!isProperType(parameterType)) {
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)expression, parameterType);
|
||||
}
|
||||
collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)expression, parameterType, !isProperType(parameterType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+160
-4
@@ -15,23 +15,32 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve.graphInference;
|
||||
|
||||
import com.intellij.psi.PsiCall;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.constraints.ExpressionCompatibilityConstraint;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InferenceSessionContainer {
|
||||
private static final Logger LOG = Logger.getInstance("#" + InferenceSessionContainer.class.getName());
|
||||
private final Map<PsiElement, InferenceSession> myNestedSessions = new HashMap<PsiElement, InferenceSession>();
|
||||
|
||||
public InferenceSessionContainer() {
|
||||
}
|
||||
|
||||
public void registerNestedSession(InferenceSession targetSession, InferenceSession session) {
|
||||
targetSession.propagateVariables(session.getInferenceVariables());
|
||||
public void registerNestedSession(InferenceSession session) {
|
||||
myNestedSessions.put(session.getContext(), session);
|
||||
myNestedSessions.putAll(session.getInferenceSessionContainer().myNestedSessions);
|
||||
}
|
||||
@@ -41,4 +50,151 @@ public class InferenceSessionContainer {
|
||||
InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(arg, PsiCall.class));
|
||||
return session == null ? defaultSession : session;
|
||||
}
|
||||
|
||||
public void registerNestedSession(InferenceSession session,
|
||||
PsiType returnType,
|
||||
PsiExpression returnExpression) {
|
||||
final InferenceSession callSession = findNestedCallSession(((PsiCallExpression)returnExpression).getArgumentList(), null);
|
||||
if (callSession == null) {
|
||||
final InferenceSession inferenceSession =
|
||||
ExpressionCompatibilityConstraint.reduceExpressionCompatibilityConstraint(session, returnExpression, returnType);
|
||||
if (inferenceSession != null && inferenceSession != session) {
|
||||
registerNestedSession(inferenceSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PsiSubstitutor infer(@NotNull PsiTypeParameter[] typeParameters,
|
||||
@NotNull PsiParameter[] parameters,
|
||||
@NotNull PsiExpression[] arguments,
|
||||
@NotNull PsiSubstitutor partialSubstitutor,
|
||||
@NotNull final PsiElement parent) {
|
||||
if (parent instanceof PsiCall) {
|
||||
final PsiExpressionList argumentList = ((PsiCall)parent).getArgumentList();
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
if (properties != null && !properties.isApplicabilityCheck()) {
|
||||
final Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>>
|
||||
session = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(parent, false,
|
||||
new Computable<Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>>>() {
|
||||
@Override
|
||||
public Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>> compute() {
|
||||
return createValue(parent);
|
||||
}
|
||||
});
|
||||
if (session != null) {
|
||||
final InitialInferenceState initialInferenceState = session.second.get(PsiTreeUtil.getParentOfType(argumentList, PsiCall.class));
|
||||
if (initialInferenceState != null) {
|
||||
|
||||
return new InferenceSession(initialInferenceState).collectAdditionalAndInfer(parameters, arguments, properties, session.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final InferenceSession inferenceSession = new InferenceSession(typeParameters, partialSubstitutor, parent.getManager(), parent);
|
||||
inferenceSession.initExpressionConstraints(parameters, arguments, parent, null);
|
||||
return inferenceSession.infer(parameters, arguments, parent);
|
||||
}
|
||||
|
||||
private static Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>> createValue(@NotNull final PsiElement parent) {
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
return startTopLevelInference(parent);
|
||||
}
|
||||
return CachedValuesManager.getCachedValue(parent,
|
||||
new CachedValueProvider<Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>>> compute() {
|
||||
return new Result<Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>>>(
|
||||
startTopLevelInference(parent), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Pair<PsiSubstitutor, Map<PsiElement, InitialInferenceState>> startTopLevelInference(@NotNull final PsiElement parent) {
|
||||
final PsiCall topLevelCall = treeWalkUp(parent);
|
||||
if (topLevelCall != null) {
|
||||
final JavaResolveResult result = topLevelCall.resolveMethodGenerics();
|
||||
if (result instanceof MethodCandidateInfo) {
|
||||
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
|
||||
final PsiParameter[] topLevelParameters = method.getParameterList().getParameters();
|
||||
final PsiExpressionList topLevelCallArgumentList = topLevelCall.getArgumentList();
|
||||
LOG.assertTrue(topLevelCallArgumentList != null, topLevelCall);
|
||||
final PsiExpression[] topLevelArguments = topLevelCallArgumentList.getExpressions();
|
||||
final InferenceSession topLevelSession =
|
||||
new InferenceSession(method.getTypeParameters(), ((MethodCandidateInfo)result).getSiteSubstitutor(), topLevelCall.getManager(), topLevelCall);
|
||||
topLevelSession.initExpressionConstraints(topLevelParameters, topLevelArguments, topLevelCall, method, ((MethodCandidateInfo)result).isVarargs());
|
||||
topLevelSession.infer(topLevelParameters, topLevelArguments, topLevelCall, ((MethodCandidateInfo)result).createProperties());
|
||||
|
||||
final Map<PsiElement, InferenceSession> nestedSessions = topLevelSession.getInferenceSessionContainer().myNestedSessions;
|
||||
Map<PsiElement, InitialInferenceState> nestedStates = new LinkedHashMap<PsiElement, InitialInferenceState>();
|
||||
for (Map.Entry<PsiElement, InferenceSession> entry : nestedSessions.entrySet()) {
|
||||
nestedStates.put(entry.getKey(), entry.getValue().createInitialState());
|
||||
}
|
||||
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
|
||||
for (InferenceVariable variable : topLevelSession.getInferenceVariables()) {
|
||||
final PsiType instantiation = variable.getInstantiation();
|
||||
if (instantiation != PsiType.NULL) {
|
||||
substitutor = substitutor.put(variable, instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
return Pair.create(substitutor, nestedStates);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiCall treeWalkUp(PsiElement context) {
|
||||
PsiCall top = null;
|
||||
PsiElement parent = PsiTreeUtil.getParentOfType(context, PsiExpressionList.class, PsiLambdaExpression.class, PsiCodeBlock.class);
|
||||
while (true) {
|
||||
if (parent instanceof PsiCodeBlock && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class) == null) {
|
||||
break;
|
||||
}
|
||||
if (parent instanceof PsiLambdaExpression) {
|
||||
boolean inReturnExpressions = false;
|
||||
for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)parent)) {
|
||||
inReturnExpressions |= PsiTreeUtil.isAncestor(expression, context, false);
|
||||
}
|
||||
if (!inReturnExpressions) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
final PsiCall psiCall = PsiTreeUtil.getParentOfType(parent, PsiCall.class);
|
||||
if (psiCall == null) {
|
||||
break;
|
||||
}
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(psiCall.getArgumentList());
|
||||
if (properties != null && properties.isApplicabilityCheck()) {
|
||||
break;
|
||||
}
|
||||
|
||||
top = psiCall;
|
||||
if (top instanceof PsiExpression && PsiPolyExpressionUtil.isPolyExpression((PsiExpression)top)) {
|
||||
parent = PsiTreeUtil.getParentOfType(parent, PsiExpressionList.class, PsiLambdaExpression.class, PsiCodeBlock.class);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (top == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiExpressionList argumentList = top.getArgumentList();
|
||||
if (argumentList == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
if (properties != null) {
|
||||
return null;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class InitialInferenceState {
|
||||
private final Set<InferenceVariable> myInferenceVariables;
|
||||
private final PsiElement myContext;
|
||||
|
||||
private final PsiSubstitutor myInferenceSubstitutor;
|
||||
private final PsiSubstitutor mySiteSubstitutor;
|
||||
private final List<Pair<PsiTypeParameter[], PsiClassType>> myCaptures;
|
||||
private final InferenceSessionContainer myInferenceSessionContainer;
|
||||
|
||||
public InitialInferenceState(Set<InferenceVariable> inferenceVariables,
|
||||
PsiElement context,
|
||||
PsiSubstitutor inferenceSubstitutor,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
List<Pair<PsiTypeParameter[], PsiClassType>> captures,
|
||||
InferenceSessionContainer inferenceSessionContainer) {
|
||||
myInferenceVariables = inferenceVariables;
|
||||
myContext = context;
|
||||
myInferenceSubstitutor = inferenceSubstitutor;
|
||||
mySiteSubstitutor = siteSubstitutor;
|
||||
myCaptures = captures;
|
||||
myInferenceSessionContainer = inferenceSessionContainer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static PsiSubstitutor copyVariables(List<InferenceVariable> targetVars,
|
||||
Set<InferenceVariable> inferenceVariables,
|
||||
PsiElement context) {
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
|
||||
final InferenceVariable[] oldVars = inferenceVariables.toArray(new InferenceVariable[inferenceVariables.size()]);
|
||||
for (InferenceVariable variable : oldVars) {
|
||||
final InferenceVariable newVariable = new InferenceVariable(context, variable.getParameter());
|
||||
substitutor = substitutor.put(variable, JavaPsiFacade.getElementFactory(variable.getProject()).createType(newVariable));
|
||||
targetVars.add(newVariable);
|
||||
}
|
||||
|
||||
for (int i = 0; i < targetVars.size(); i++) {
|
||||
InferenceVariable var = targetVars.get(i);
|
||||
for (InferenceBound boundType : InferenceBound.values()) {
|
||||
for (PsiType bound : oldVars[i].getBounds(boundType)) {
|
||||
var.addBound(substitutor.substitute(bound), boundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return substitutor;
|
||||
}
|
||||
|
||||
public InferenceSessionContainer getInferenceSessionContainer() {
|
||||
return myInferenceSessionContainer;
|
||||
}
|
||||
|
||||
public Set<InferenceVariable> getInferenceVariables() {
|
||||
return myInferenceVariables;
|
||||
}
|
||||
|
||||
public PsiElement getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
||||
public PsiSubstitutor getInferenceSubstitutor() {
|
||||
return myInferenceSubstitutor;
|
||||
}
|
||||
|
||||
public PsiSubstitutor getSiteSubstitutor() {
|
||||
return mySiteSubstitutor;
|
||||
}
|
||||
|
||||
public List<Pair<PsiTypeParameter[], PsiClassType>> getCaptures() {
|
||||
return myCaptures;
|
||||
}
|
||||
}
|
||||
+19
-6
@@ -18,6 +18,7 @@ package com.intellij.psi.impl.source.resolve.graphInference;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -38,9 +39,22 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
|
||||
@NotNull PsiSubstitutor partialSubstitutor,
|
||||
@Nullable PsiElement parent,
|
||||
@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).substitute(typeParameter);
|
||||
final PsiSubstitutor substitutor;
|
||||
if (parent != null) {
|
||||
substitutor = inferTypeArguments(new PsiTypeParameter[]{typeParameter},
|
||||
parameters,
|
||||
arguments,
|
||||
partialSubstitutor,
|
||||
parent,
|
||||
policy,
|
||||
PsiUtil.getLanguageLevel(parent));
|
||||
}
|
||||
else {
|
||||
final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager, null);
|
||||
inferenceSession.initExpressionConstraints(parameters, arguments, null, null);
|
||||
substitutor = inferenceSession.infer();
|
||||
}
|
||||
return substitutor.substitute(typeParameter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -53,9 +67,8 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
|
||||
@NotNull ParameterTypeInferencePolicy policy,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
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);
|
||||
|
||||
return InferenceSessionContainer.infer(typeParameters, parameters, arguments, partialSubstitutor, parent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+58
-52
@@ -82,58 +82,13 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
}
|
||||
|
||||
if (myExpression instanceof PsiCall) {
|
||||
final PsiExpressionList argumentList = ((PsiCall)myExpression).getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
PsiType returnType = null;
|
||||
PsiTypeParameter[] typeParams = null;
|
||||
final JavaResolveResult resolveResult = candidateProperties != null ? null : InferenceSession.getResolveResult((PsiCall)myExpression);
|
||||
PsiMethod method = null;
|
||||
if (candidateProperties != null) {
|
||||
method = candidateProperties.getMethod();
|
||||
}
|
||||
else {
|
||||
final PsiElement element = resolveResult.getElement();
|
||||
if (element instanceof PsiMethod) {
|
||||
method = (PsiMethod)element;
|
||||
}
|
||||
}
|
||||
|
||||
if (method != null && !method.isConstructor()) {
|
||||
returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
}
|
||||
else if (resolveResult != null) {
|
||||
final PsiClass psiClass = method != null ? method.getContainingClass() : (PsiClass)resolveResult.getElement();
|
||||
if (psiClass != null) {
|
||||
returnType = JavaPsiFacade.getElementFactory(argumentList.getProject()).createType(psiClass, PsiSubstitutor.EMPTY);
|
||||
typeParams = psiClass.getTypeParameters();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeParams != null) {
|
||||
PsiSubstitutor siteSubstitutor = InferenceSession.chooseSiteSubstitutor(candidateProperties, resolveResult, method);
|
||||
final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, myExpression.getManager(), myExpression);
|
||||
callSession.propagateVariables(session.getInferenceVariables());
|
||||
if (method != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
callSession.initExpressionConstraints(parameters, args, myExpression, method, InferenceSession
|
||||
.chooseVarargsMode(candidateProperties, resolveResult));
|
||||
}
|
||||
final boolean accepted = callSession.repeatInferencePhases(true);
|
||||
if (!accepted) {
|
||||
return false;
|
||||
}
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), myT);
|
||||
if (callSession.repeatInferencePhases(true)) {
|
||||
session.getInferenceSessionContainer().registerNestedSession(session, callSession);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
final InferenceSession callSession = reduceExpressionCompatibilityConstraint(session, myExpression, myT);
|
||||
if (callSession == null) {
|
||||
return false;
|
||||
}
|
||||
if (callSession != session) {
|
||||
session.getInferenceSessionContainer().registerNestedSession(callSession);
|
||||
session.propagateVariables(callSession.getInferenceVariables());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -152,6 +107,57 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
return true;
|
||||
}
|
||||
|
||||
public static InferenceSession reduceExpressionCompatibilityConstraint(InferenceSession session,
|
||||
PsiExpression expression,
|
||||
PsiType targetType) {
|
||||
final PsiExpressionList argumentList = ((PsiCall)expression).getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
PsiType returnType = null;
|
||||
PsiTypeParameter[] typeParams = null;
|
||||
final JavaResolveResult resolveResult = candidateProperties != null ? null : InferenceSession.getResolveResult((PsiCall)expression);
|
||||
final PsiMethod method = InferenceSession.getCalledMethod((PsiCall)expression);
|
||||
|
||||
if (method != null && !method.isConstructor()) {
|
||||
returnType = method.getReturnType();
|
||||
if (returnType != null) {
|
||||
typeParams = method.getTypeParameters();
|
||||
}
|
||||
}
|
||||
else if (resolveResult != null) {
|
||||
final PsiClass psiClass = method != null ? method.getContainingClass() : (PsiClass)resolveResult.getElement();
|
||||
if (psiClass != null) {
|
||||
returnType = JavaPsiFacade.getElementFactory(argumentList.getProject()).createType(psiClass, PsiSubstitutor.EMPTY);
|
||||
typeParams = psiClass.getTypeParameters();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeParams != null) {
|
||||
PsiSubstitutor siteSubstitutor = InferenceSession.chooseSiteSubstitutor(candidateProperties, resolveResult, method);
|
||||
final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, expression.getManager(), expression);
|
||||
callSession.propagateVariables(session.getInferenceVariables());
|
||||
if (method != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
callSession.initExpressionConstraints(parameters, args, expression, method, InferenceSession
|
||||
.chooseVarargsMode(candidateProperties, resolveResult));
|
||||
}
|
||||
final boolean accepted = callSession.repeatInferencePhases(true);
|
||||
if (!accepted) {
|
||||
return null;
|
||||
}
|
||||
callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
|
||||
if (callSession.repeatInferencePhases(true)) {
|
||||
return callSession;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
+9
@@ -3,6 +3,7 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSessionContainer;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
|
||||
import java.util.List;
|
||||
@@ -69,6 +70,14 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
|
||||
constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (PsiExpression returnExpression : returnExpressions) {
|
||||
if (returnExpression instanceof PsiCallExpression) {
|
||||
final InferenceSessionContainer sessionContainer = session.getInferenceSessionContainer();
|
||||
sessionContainer.registerNestedSession(session, returnType, returnExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ class NachCollections<K,V> {
|
||||
Collection<? super Map.Entry<K,V>> c2,
|
||||
Consumer<Map.Entry<K, V>> a) {
|
||||
c1.forEach(consumer(a));
|
||||
c2.forEach(consumer<error descr="'consumer(java.util.function.Consumer<java.util.Map.Entry<K1,V1>>)' in 'NachCollections' cannot be applied to '(java.util.function.Consumer<java.util.Map.Entry<K,V>>)'">(a)</error>);
|
||||
c2.forEach<error descr="'forEach(java.util.function.Consumer<capture<? super java.util.Map.Entry<K,V>>>)' in 'java.lang.Iterable' cannot be applied to '(java.util.function.Consumer<java.util.Map.Entry<K,V>>)'">(consumer(a))</error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ class TestIDEA128101 {
|
||||
|
||||
public static void test() {
|
||||
construct(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
construct1(String.class, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.Integer>)'">(integerAttribute)</error>, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.String>)'">(stringAttribute)</error>);
|
||||
construct1(String.class, createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.Integer>)'">(integerAttribute)</error>, createPath(stringAttribute));
|
||||
construct2(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
<error descr="Type parameter K has incompatible upper bounds: Integer and String">construct3(String.class, createPath(integerAttribute), createPath(stringAttribute));</error>
|
||||
<error descr="Type parameter K has incompatible upper bounds: Integer and String">construct4(String.class, createPath(integerAttribute), createPath(stringAttribute));</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<M1>, ConcurrentCollectors.BiConsumer<M1,T>, ConcurrentCollectors.BiOp<M1>)' 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
@@ -32,7 +32,7 @@ class Test1 {
|
||||
}
|
||||
|
||||
{
|
||||
bar(l -> baz<error descr="'baz(java.lang.Object)' in 'Test1' cannot be applied to '(<lambda parameter>)'">(l)</error>);
|
||||
bar(l -> <error descr="Unhandled exception: Test1.MyEx">baz(l)</error>);
|
||||
bar(<error descr="Unhandled exception: Test1.MyEx">this::baz</error>);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ abstract class NoFormalParamTypeInferenceNeeded {
|
||||
zip(a -> zip(text -> text));
|
||||
Integer zip = zip(a -> zip(<error descr="inference variable R has incompatible bounds:
|
||||
lower bounds: Object
|
||||
upper bounds: Object, R">text -> text</error>));
|
||||
upper bounds: Object, R, Integer">text -> text</error>));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ public class Bug
|
||||
{
|
||||
final I<CRN> f = null;
|
||||
|
||||
Bug.<String>create(fn<error descr="'fn(Bug.I<FN>)' 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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user